Projection middleware checks for null on non-nullable field, resulting in exception for complex type in EF Core 8
Is there an existing issue for this?
- [X] I have searched the existing issues
Product
Hot Chocolate
Describe the bug
The projection middleware is generating this query:
DbSet<User>()
.Where(u => u.Id == __query_EntityId_0)
.Select(_s1 => new User{
Id = _s1.Id,
Username = _s1.Username,
EmailAddress = _s1.EmailAddress,
AccountStatus = _s1.AccountStatus != null ? new UserAccountStatus{ IsRegistrationCompleted = _s1.AccountStatus.IsRegistrationCompleted }
: null
}
)
Which results in an EF Core 8 exception when using complex types:
System.InvalidOperationException: Comparing complex types to null is not supported.
User.AccountStatus is non-nullable, so it shouldn't be checking for null like this.
Steps to reproduce
I'll provide a reproduction repository if it helps, but it's probably not necessary.
Relevant log output
No response
Additional Context?
No response
Version
13.5.1
@PascalSenn Would you be able to point to the code that is responsible for adding this null check?
This exception is a bit weird. If i remember correctly we deliberately added the null-checks back because of some EF Core behaviour.
The visitor is able to "skip all null checks":
https://github.com/ChilliCream/graphql-platform/blob/3f7f16001a275117117f24d4bd4891cb0a26cc9e/src/HotChocolate/Data/src/Data/Projections/Expressions/Handlers/QueryableProjectionFieldHandler.cs#L93-L104
but in the case of ef core we added it back:
https://github.com/ChilliCream/graphql-platform/blob/3f7f16001a275117117f24d4bd4891cb0a26cc9e/src/HotChocolate/Data/src/Data/Projections/Expressions/QueryableProjectionProvider.cs#L85
Do you have a stacktrace for the exception?
does it work when we use default?
System.InvalidOperationException: Comparing complex types to null is not supported.
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.<>c__DisplayClass62_0.<TryRewriteStructuralTypeEquality>g__TryRewriteComplexTypeEquality|1(Expression& result)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TryRewriteStructuralTypeEquality(ExpressionType nodeType, Expression left, Expression right, Boolean equalsMethod, Expression& result)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
at Npgsql.EntityFrameworkCore.PostgreSQL.Query.Internal.NpgsqlSqlTranslatingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.VisitConditional(ConditionalExpression conditionalExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateInternal(Expression expression, Boolean applyDefaultTypeMapping)
at Microsoft.EntityFrameworkCore.Query.RelationalSqlTranslatingExpressionVisitor.TranslateProjection(Expression expression, Boolean applyDefaultTypeMapping)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberAssignment(MemberAssignment memberAssignment)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberBinding(MemberBinding node)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitMemberInit(MemberInitExpression memberInitExpression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at HotChocolate.Data.Projections.SingleOrDefaultMiddleware`1.InvokeAsync(IMiddlewareContext context)
at HotChocolate.Utilities.MiddlewareCompiler`1.ExpressionHelper.AwaitTaskHelper(Task task)
at HotChocolate.Execution.Processing.Tasks.ResolverTask.ExecuteResolverPipelineAsync(CancellationToken cancellationToken)
at HotChocolate.Execution.Processing.Tasks.ResolverTask.TryExecuteAsync(CancellationToken cancellationToken)
I believe default has the same issue.