Filtering: `FilterExpressionBuilder.HasValue` / `HasValueAndAlso` wrap `HasValue` in `Expression.IsTrue`, which EF Core cannot translate
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 75/100
Research direction
Start with src/HotChocolate/Data/src/Data/Filters/Expressions/FilterExpressionBuilder.cs, especially HasValue and HasValueAndAlso. Run the linked reproduction script against the reported EF Core setup and inspect how the expressions differ from the translating NotNull helpers. Done means both HasValue helpers translate on EF Core and the reproduction succeeds.
Written by the indexing model from the issue text.
Description
Product
Hot Chocolate
Version
16.6.8
Link to minimal reproduction
Steps to reproduce
- Clone the repository and run
./hotchocolate-data-hasvalue-istrue-efcore/repro.sh(bash; Git Bash works on Windows). It runsdotnet runon a console project referencingHotChocolate.Data16.6.8 andMicrosoft.EntityFrameworkCore.Sqlite10.0.13, with an in-memory SQLite database; no server is needed. - The program builds four predicates over
Order.Quantity(int?) with the publicFilterExpressionBuilder, the helper a customQueryableOperationHandlerBasebuilds its expression with, and runs each in memory and through EF Core:
var order = Expression.Parameter(typeof(Order), "o");
var quantity = Expression.Property(order, nameof(Order.Quantity)); // int?
var greaterThanFive = Expression.GreaterThan(
Expression.Property(quantity, nameof(Nullable<int>.Value)), Expression.Constant(5));
FilterExpressionBuilder.HasValueAndAlso(quantity, greaterThanFive); // fails on EF Core
FilterExpressionBuilder.HasValue(quantity); // fails on EF Core
FilterExpressionBuilder.NotNullAndAlso(quantity, greaterThanFive); // translates
Expression.AndAlso(Expression.Property(quantity, "HasValue"), greaterThanFive); // translates
REPRO_HC_VERSION=16.7.0-p.28 ./repro.shruns the same against the latest 16.7 preview.
What is expected?
HasValue(x) and HasValueAndAlso(x, condition) translate on EF Core like NotNull(x) and NotNullAndAlso(x, condition) do, to x IS NOT NULL: EF Core translates Nullable<T>.HasValue itself.
What is actually happening?
FilterExpressionBuilder.HasValue returns Expression.IsTrue(Expression.Property(expression, "HasValue")). EF Core has no translation for a UnaryExpression of node type IsTrue, so any filter built with HasValue or HasValueAndAlso throws The LINQ expression ... could not be translated on a relational provider. In memory the four predicates agree. Same result on 16.7.0-p.28; main has the same code (src/HotChocolate/Data/src/Data/Filters/Expressions/FilterExpressionBuilder.cs, HasValue).
Relevant log output
== FilterExpressionBuilder.HasValueAndAlso(o.Quantity, o.Quantity.Value > 5)
expression: o => (IsTrue(o.Quantity.HasValue) AndAlso (o.Quantity.Value > 5))
in memory: [3]
EF Core: !! InvalidOperationException: The LINQ expression 'DbSet<Order>()
.Where(o => IsTrue(o.Quantity.HasValue) && o.Quantity.Value > 5)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
== FilterExpressionBuilder.HasValue(o.Quantity)
expression: o => IsTrue(o.Quantity.HasValue)
in memory: [1, 3]
EF Core: !! InvalidOperationException: The LINQ expression 'DbSet<Order>()
.Where(o => IsTrue(o.Quantity.HasValue) )' could not be translated. [...]
== FilterExpressionBuilder.NotNullAndAlso(o.Quantity, o.Quantity.Value > 5)
expression: o => ((o.Quantity != null) AndAlso (o.Quantity.Value > 5))
in memory: [3]
EF Core: [3]
SQL: WHERE "o"."Quantity" IS NOT NULL AND "o"."Quantity" > 5
== Expression.AndAlso(o.Quantity.HasValue, o.Quantity.Value > 5), no IsTrue
expression: o => (o.Quantity.HasValue AndAlso (o.Quantity.Value > 5))
in memory: [3]
EF Core: [3]
SQL: WHERE "o"."Quantity" IS NOT NULL AND "o"."Quantity" > 5
Additional context
HotChocolate.Data does not call HasValue or HasValueAndAlso itself (they came with #5760 and nothing in src/HotChocolate/Data uses them; the built-in handlers guard a nullable instance with NotNullAndAlso), so this only reaches custom operation handlers, for which FilterExpressionBuilder is the public toolbox. We hit it in a handler filtering a Nullable<TStruct> member and switched to x != null. Dropping the Expression.IsTrue wrapper (HasValue is already a bool) would make both helpers translate.
Investigation and write-up assisted by Claude (Anthropic); the linked repro was run on Windows 11 (10.0.26200), .NET SDK 10.0.402, HotChocolate.Data 16.6.8 and 16.7.0-p.28, Microsoft.EntityFrameworkCore.Sqlite 10.0.13, and I reviewed this report.
- Dominant language
- C#
- Stars
- 5.8k
- Forks
- 810
- Avg merge
- 19h 37m
- Merged PRs (30d)
- 156
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from ChilliCream/graphql-platform
-
Make `TryInferSchemaType` on `IDescriptorContext` public for use in custom type discovery handlersOpen🌶️ hot chocolate
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
ChilliCream/graphql-platform#10569 ·
Maintainers usually reply within 1 day
-
HC16: @defer with incremental delivery v0.1 exposes a lifetime race that can cause persistent high CPUPossibly taken @tobias-tengler claimed this 7 days ago. Open🌶️ hot chocolate
ChilliCream/graphql-platform#10668 · 1 comment · 1 assignee ·
Maintainers usually reply within 1 day
-
🌶️ strawberry shake
Difficulty 5/5 Over a week Newbie friendliness 35/100
ChilliCream/graphql-platform#10643 ·
Maintainers usually reply within 1 day
-
🌶️ strawberry shake
Difficulty 3/5 1-2 days Newbie friendliness 76/100
ChilliCream/graphql-platform#10570 ·
Maintainers usually reply within 1 day
-
Cost analysis: let a custom filter operation be weighed as expensive (`DefaultExpensiveFilterOperationCost`)Possibly taken @michaelstaib claimed this 9 days ago. Open🌶️ hot chocolate
Difficulty 3/5 1-2 days Newbie friendliness 68/100
ChilliCream/graphql-platform#10568 · 1 assignee ·
Maintainers usually reply within 1 day
All issues in ChilliCream/graphql-platform
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
bug 優先: 低
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 92/100
-
.NET area: storage bug good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Larson-Logan/medal-sync#61 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
Maintainers usually reply within 1 day