When using a ternary if in combination with an inner .Select(...).ToList(), an ArgumentNullException is thrown. This seems to only happen with an InMemory database and did not appear with SqlServer.
This issue was originally found by testing some code using AutoMapper with nested entities, the original issue can be found here: AutoMapper/AutoMapper#3309
Possibly related to #9223.
Within an InMemory database, execute a query that contains a ternary if which contains another expression using .Select(...).ToList(), like the following:
var alphaDtosQuery = dbContext.Alphas
.Select(alpha => (alpha.Bravos.Count > 0) ? null : new AlphaDto
{
Bravos = alpha.Bravos
.Select(bravo => new BravoDto())
.ToList()
});
var alphaDtos = alphaDtosQuery.ToList();
The following exception is thrown (click to open):
System.ArgumentNullException
HResult=0x80004003
Message=Value cannot be null. (Parameter 'bindings')
Source=System.Linq.Expressions
StackTrace:
at System.Linq.Expressions.Expression.ValidateMemberInitArgs(Type type, ReadOnlyCollection`1 bindings)
at System.Linq.Expressions.Expression.MemberInit(NewExpression newExpression, IEnumerable`1 bindings)
at System.Linq.Expressions.MemberInitExpression.Update(NewExpression newExpression, IEnumerable`1 bindings)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryExpressionTranslatingExpressionVisitor.VisitConditional(ConditionalExpression conditionalExpression)
at System.Linq.Expressions.ConditionalExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryExpressionTranslatingExpressionVisitor.Translate(Expression expression)
at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryProjectionBindingExpressionVisitor.Visit(Expression expression)
at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryProjectionBindingExpressionVisitor.Translate(InMemoryQueryExpression queryExpression, Expression expression)
at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
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__DisplayClass9_0`1.<Execute>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at MinimalTest.MinimalTest.TestWithTernary() in D:\Some\File\Path\MinimalTest.cs:line 107
Remove the .Select(...) or the ternary if, and the query will be executed just fine.
A sub 100loc repro can be found here:
https://gist.github.com/BaerMitUmlaut/a5feed7af2132b5e5f7d31cd4e7cc08b
EF Core version: 3.0.0 and 3.1.1
Database provider: Microsoft.EntityFrameworkCore.InMemory
Target framework: .NET Core 3.0
Operating system: Windows 10
IDE: Visual Studio 2019 Professional 16.4.3
@maumar to take a look.
problem is that InMemoryExpressionTranslatingExpressionVisitor is not correctly handling MemberInit expression node. Subquery:
alpha.Bravos
.Select(bravo => new BravoDto())
.ToList()
can't be translated, so the binding expression returns null. However default implementation of VisitMemberInit doesn't account for null binding, so the exception is thrown. Instead, we should handle it, similar to what InMemoryProjectionBindingExpressionVisitor is doing.
Duplicate of https://github.com/dotnet/efcore/issues/19316
Still in 5.0 rc1.
I get hit by this in unit tests every time I forget to add DoNotAllowNull() in the AutoMapper configuration option for a one-to-one relationship marked with [Required]. It works in SQL Server provider, but not in InMemory.
Any progress on this?
@smitpatel Is this really a duplicate of #19316? If so, can we close this one?
@joakimriedel This issue is in the Backlog milestone. This means that it is not planned for the next release (EF Core 5.0). We will re-assess the backlog following the this release and consider this item at that time. However, keep in mind that there are many other high priority features with which it will be competing for resources.
@ajcvickers no stress, the workaround helps and it's only affecting unit tests for us.
But it would be nice to have it fixed, since I have a bad memory and always forget to add the workaround in new queries - and then spend 30 minutes to find this very same issue to remind me how to fix it. 😉
edit: that said - I just looked at #19316 and I did not understand how this could be a duplicate of that - the exception and stacktrace is totally different. I get the _"Value cannot be null. (Parameter 'bindings')"_ like @BaerMitUmlaut posted in this issue.
If what @maumar wrote is the cause (and I agree with @joakimriedel, the exception would match better than the one from #19316), I could take a shot at this. Would a PR help with getting this into 5.1?
@BaerMitUmlaut There is no 5.1 planned. The next release after EF Core 5.0 is planned to be EF Core 6.0 in November 2021.
What's a workaround when not using AutoMapper? Loading the result to memory first using .ToList() and then selecting on the enumerable instead of the queryable?
@yousiftouma From the original post, where AutoMapper has aleardy been removed:
Remove the .Select(...) or the ternary if, and the query will be executed just fine.
@yousiftouma From the original post, where AutoMapper has aleardy been removed:
Remove the .Select(...) or the ternary if, and the query will be executed just fine.
What if I cannot remove the ternary (i.e., I have a column in my DB that can be null), but I still have to use Select because I need to map my entities to DTOs?
@yousiftouma From the original post, where AutoMapper has aleardy been removed:
Remove the .Select(...) or the ternary if, and the query will be executed just fine.
What if I cannot remove the ternary (i.e., I have a column in my DB that can be null), but I still have to use Select because I need to map my entities to DTOs?
For now, I'm querying as entity then mapping the entity to DTO (see example below).
Looking forward for a definitive solution for this issue :)
var entity = await context.Entities
.Where(...) // some condition
.Include(...) // necessary nested entities
.FirstOrDefaultAsync();
if (entity != null)
{
return new MyDTO
{
// filling necessary DTO fields, including nested DTOs
};
}
This is likely fixed in main
@smitpatel I don't think so, I just had this problem a few days ago after adding a many-many relationship on he latest packages.
@worthy7 - Without looking at repro code which may or may not be duplicate of this and knowing which exact package you tried, it would hard to make a claim that this is not fixed. Query can throw same exception for very different kind of bugs too.
Using original post code from here: https://gist.github.com/BaerMitUmlaut/a5feed7af2132b5e5f7d31cd4e7cc08b

If it's a duplicate fair enough to close.
@worthy7 main branch has 6.0 alpha packages. I am not referring to 5.0 release.
Ah, ok thanks.
On Fri, 4 Dec 2020, 15:40 Smit Patel, notifications@github.com wrote:
@worthy7 https://github.com/worthy7 main branch has 6.0 alpha packages.
I am not referring to 5.0 release.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/dotnet/efcore/issues/19726#issuecomment-738598622,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ABEKWH2WYMWMKYOUV37KDDTSTB74HANCNFSM4KMRC22Q
.
I've had this issue with AutoMapper and Mapster in EF Core 3 & 5 - mainly in the unit tests that use InMemory.
With the latest daily build of EF Core 6 the tests are finally passing though, so I am fairly certain that this has been fixed.