Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Execute SingleOrDefault query on database #5566

Open
1 task done
xmasctf opened this issue Nov 29, 2022 · 3 comments · May be fixed by #6833
Open
1 task done

Execute SingleOrDefault query on database #5566

xmasctf opened this issue Nov 29, 2022 · 3 comments · May be fixed by #6833
Labels
Area: Data Issue is related to filtering, sorting, pagination or projections 🐛 bug Something isn't working 🌶️ hot chocolate

Comments

@xmasctf
Copy link

xmasctf commented Nov 29, 2022

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Hi,

I'm trying to optimize my SingleOrDefault() query to the database, but can not get desired result.

I created that GraphQL query, which is giving me correct result, besides that Projection is working well too, so only columns provided are also returned. What bother me is when I look at the generated SQL query, it looks like all the items that satisfy .Where() condition are loaded into memory, and then SingleOrDefault() is executed.

My C# code:

[UseDbContext(typeof(AccountDbContext))]
[UseSingleOrDefault]
[UseProjection]
public IQueryable<AccountType> GetById(
    int id,
    [ScopedService] AccountDbContext context)
{
    return context.Accounts
        .Where(x => x.Id == id)
        .Select(x => new AccountType
        {
            Id = x.Id,
            Name = x.Name,
            Country = x.Country,
            Email = x.Email
        });
}

Generated SQL:

SELECT [a].[Id], [a].[Name], [a].[Country], [a].[Email]
      FROM [Accounts] AS [a]
      WHERE [a].[Id] = @__id_0

If I try with another code, then SingleOrDefault() is performed on database, but the thing is that Projection stops working. I am aware that Projections are working only on IQueryable, and that is the reason why it returns all of the columns from DB.

Antoher C# example:

[UseDbContext(typeof(AccountDbContext))]
[UseProjection]
public AccountType GetById(
    int id,
    [ScopedService] AccountDbContext context)
{
    var x = context.Accounts
       .SingleOrDefault(x => x.Id == id);

    return new AccountType
    {
        Id = x.Id,
        Name = x.Name,
        Country = x.Country,
        Email = x.Email
    };
}

And generated SQL statement:

SELECT TOP(2) [a].[Id], [a].[Country], [a].[CreatedAt], [a].[Email], [a].[LastChangedAt], [a].[Name]
      FROM [Accounts] AS [a]
      WHERE [a].[Id] = @__id_0

As you can see this is whole different query performed on database level, but in this case Projection stops working. If I instead of searching by int id use [UseFiltering] attribute the things are still working the same way as in 1st case.

Is there something I am missing out, am I interpreting SQL statements in a wrong way, or is the query I am trying to achieve impossible using HotChocolate?

Thank you for help.

Am I missing something, o

Steps to reproduce

I provided all the source code in descrpiton of bug.

Relevant log output

No response

Additional Context?

No response

Product

Hot Chocolate

Version

12

@xmasctf xmasctf added the 🐛 bug Something isn't working label Nov 29, 2022
@michaelstaib
Copy link
Member

The code you provided looks good ... not sure whats wrong. Can you create a little repro and attach it to the issue?

@michaelstaib michaelstaib added 🌶️ hot chocolate Area: Data Issue is related to filtering, sorting, pagination or projections labels Nov 29, 2022
@xmasctf
Copy link
Author

xmasctf commented Nov 30, 2022

The code you provided looks good ... not sure whats wrong. Can you create a little repro and attach it to the issue?

@michaelstaib here I prepared small repro for you, this time using SQL Lite instead of Azure SQL. Migrations and DB seeding should be executed on startup.

These are all possible queries to execute on BananaCakePop.

query getAll {
  all {
    id
    name
  }
}

query getById {
  byId(id: 1) {
    id
    name
  }
}

query getByIdX {
  byIdX(id: 1) {
    id
    name
  }
}

If you check getById query, you can see, that the generated SQL statement is:

SELECT "a"."Id", "a"."Name"
      FROM "Accounts" AS "a"
      WHERE "a"."Id" = @__id_0

And if you check getByIdX, you will see that the generated SQL looks like:

 SELECT "a"."Id", "a"."Country", "a"."CreatedAt", "a"."Email", "a"."LastChangedAt", "a"."Name"
      FROM "Accounts" AS "a"
      WHERE "a"."Id" = @__id_0
      LIMIT 2

As I said in previous post, for me it looks like 1st query loads all the items that satisfy condition to memory, and then performs SingleOrDefault on data that are already in memory. In 2nd case, there is different query, where SingleOrDefault is performed on DB layer, but projection isn't working.

I may be wrong, or maybe I don't understand how each of those SQL statements works, so that's why I am asking for help.

@glen-84
Copy link
Collaborator

glen-84 commented Oct 26, 2023

@michaelstaib @PascalSenn

I looked into this a bit (using mostly v13), and there does appear to be quite a critical issue with the [UseFirstOrDefault] attribute. [UseSingleOrDefault] is less affected since that is usually used when filtering on unique values.

[UseFirstOrDefault]

This executes the query without a limit. This means that it could load an entire table into memory ⚠️, only to return a single row.

It should be setting the limit/take to 1.

[UseSingleOrDefault]

This also executes the query without a limit. If the column is unique, then it's not an issue. If the column is not unique, then it will load all matching data ⚠️, and then return a Sequence contains more than one element. error (expected).

Ideally, it should be setting the limit/take to 2.


@xmasctf For getByIdX, projection won't work since you're not returning an IQueryable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Data Issue is related to filtering, sorting, pagination or projections 🐛 bug Something isn't working 🌶️ hot chocolate
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants