When doing this, also make sure the scenario from #5883 is taken care of - dotting thru an optional nav to get a value
If you have a model (see attached project) with class A with a nullable id field for child class E - int? EId, querying A->E fails with "argument types do not match" error.
c#
var item =
(from a
in db.As
select new A
{
Id = a.Id,
EId = a.EId,
E = new E
{
Id = a.E.Id
}
}
).First();
In attached project query_ef_test_ac fails with the following information:
Test Name: BugDemoEF.EFTest.query_ef_test_ae
Test FullName: BugDemoEF.EFTest.query_ef_test_ae
Test Source: C:\Code\General\BugDemo\src\BugDemoEF\EFTests.cs : line 205
Test Outcome: Failed
Test Duration: 0:00:01.976
Result StackTrace:
at System.Linq.Expressions.Expression.Bind(MemberInfo member, Expression expression)
at System.Linq.Expressions.ExpressionVisitor.VisitT
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberAssignment(MemberAssignment node)
at System.Linq.Expressions.ExpressionVisitor.VisitT
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at Remotion.Linq.Clauses.SelectClause.TransformExpressions(Func2 transformation)
at Remotion.Linq.QueryModelVisitorBase.VisitQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.NavigationRewritingExpressionVisitor.Rewrite(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.OptimizeQueryModel(QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.CreateQueryExecutor[TResult](QueryModel queryModel)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass19_01.
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryTResult
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteTResult
at BugDemoEF.EFTest.query_ef_test_ae() in C:\Code\General\BugDemo\src\BugDemoEF\EFTests.cs:line 208
Result Message: Argument types do not match
the problem is in here
E = new E
{
Id = a.E.Id
}
Because a.E is optional navigation, a.E.Id can potentially be null. To compensate we convert the calls to int? and now we are trying to fit int? into int column.
Workaround is to use anonymous type instead:
var item =
(from a
in db.As
select new
{
Id = a.Id,
EId = a.EId,
E = new
{
Id = (int?)a.E.Id
}
}
).First();
Talking to @maumar and @ajcvickers, we don't feel like this is RTM, because of the workaround and it doesn't seem to be that common. Thoughts?
cc @rowanmiller @anpete
Thank you for the quick response.
This actually doesn't solve the problem at all and is a major issue. My objective is to return a new E class, not a new anonymous class similar to E. A detached instance is going to the client as a web service result.
I also tried using a nullable syntax in the query e.g.
E = (a.EId.HasValue ? return new E {} etc, null)
but that didn't work either.
To resolve this, I would have to then map the result to the strong type definition and I can't use Automapper for anonymous types.
This results in a ton of extra code and manual maintenance.
Try this solution:
var item =
(from a
in db.As
select new A
{
Id = a.Id,
EId = a.EId,
E = new E
{
Id = (int)((int?)a.E.Id ?? 0)
}
}
).First();
Generates following query
SELECT [a].[Id], [a].[CId], [a].[DId], [a].[EId], [a.E].[Id], 0
FROM [As] AS [a]
LEFT JOIN [Es] AS [a.E] ON [a].[EId] = [a.E].[Id]
ORDER BY [a].[EId]
And does not throw above exception. ToList() version runs without any exception. (First() fails for me because my database doesn't have any data.)
Nope – the moment I add in the additional fields, it fails with the same error. The problem seems to be a lot deeper than just the key field and it applies to any model that has a parent with an optional child.
B.
From: Smit Patel [mailto:[email protected]]
Sent: Friday, May 27, 2016 2:22 PM
To: aspnet/EntityFramework [email protected]
Cc: brianro [email protected]; Author [email protected]
Subject: Re: [aspnet/EntityFramework] Model with nullable FK fails parent child query with "Argument Types do not match" (#5522)
Try this solution:
var item =
(from a
in db.As
select new A
{
Id = a.Id,
EId = a.EId,
E = new E
{
Id = (int)((int?)a.E.Id ?? 0)
}
}
).First();
Generates following query
SELECT [a].[Id], [a].[CId], [a].[DId], [a].[EId], [a.E].[Id], 0
FROM [As] AS [a]
LEFT JOIN [Es] AS [a.E] ON [a].[EId] = [a.E].[Id]
ORDER BY [a].[EId]
And does not throw above exception. ToList() version runs without any exception. (First() fails for me because my database doesn't have any data.)
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub https://github.com/aspnet/EntityFramework/issues/5522#issuecomment-222232407 , or mute the thread https://github.com/notifications/unsubscribe/ADYRDDmoIeIXaaDdKjxe6pI8r2NxDU6wks5qF0R0gaJpZM4Im7fi . https://github.com/notifications/beacon/ADYRDC4lDkcVa-WRh5SzZeXN9WsUBtEMks5qF0R0gaJpZM4Im7fi.gif
As @maumar described above
A.E is option navigation. (due to Int32? a nullable type being FK property). Therefore A.E.Id can have null value and the result value is nullable type of whatever is type of A.E.Id. And that applies to all the properties of E.
Therefore based on what you want,
This should be the work-around.
var item =
(from a
in db.As
select new A
{
Id = a.Id,
EId = a.EId,
E = a.EId.HasValue ?
new E
{
Id = (int)a.E.Id
// if you add more property which are of non-nullable type, then explicit cast is needed
}: null
}
).ToList();
For further properties added inside new E you need to cast the properties if they are of non-nullable type since a.E.Property is still nullable type. That should work properly. (I tested above code in the project you provided and it works fine).
We can still do something about explicit cast not being required but work-around should be good enough for now.
@smitpatel - this solutions works thanks ... uglifies my code but its functional.
@brianro with https://github.com/aspnet/EntityFramework/commit/a24f9bc12c549d03499c2524fe2e3c57a4832c73 checked in, you should be able to just use coalesce, without any casting or HasValue checks. This is currently available in out nightly builds and will also be available in the next release
Super news - thank you so much for getting that knocked out.
As always, I appreciate your attentiveness and dedication.
B.
When doing this, also make sure the scenario from https://github.com/aspnet/EntityFramework/issues/5883 is taken care of - dotting thru an optional nav to get a value
fixed in 7d359abdca1046a41c1cdffed1a88d80af99fed1
I'm running into a similar problem and I've tried all the workarounds and fixes but none of them worked. Here is my code and bear in mind I'm getting the same error.
https://gist.github.com/DmsChrisPena/a8bfa560f5c2bd2565a778a67018dcd1
@DmsChrisPena the issue being tracked here is fixed. If you are still seeing the failure on our nightly builds, then please open a new issue with details.
Most helpful comment
the problem is in here
Because a.E is optional navigation, a.E.Id can potentially be null. To compensate we convert the calls to int? and now we are trying to fit int? into int column.
Workaround is to use anonymous type instead: