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

IncludeOptimized Multiple Levels #715

Open
cangunaydin opened this issue Jan 23, 2022 · 2 comments
Open

IncludeOptimized Multiple Levels #715

cangunaydin opened this issue Jan 23, 2022 · 2 comments
Assignees

Comments

@cangunaydin
Copy link

1. Description

Hello after i upgraded my project to .net 6.0 and ef core 6.0, i was facing issue on the includeoptimized so normally what we have written before was breaking. here is an example code that we use

efContext.Offers.IncludeOptimized(o => o.OfferItems.Select(
                     oi => oi.OfferItemScreenTenants.Select(oist => oist.ScreenTenant)
                     )).FirstOrDefaultAsync(o => o.GroupId == offerGroupId && o.Status != OfferStatus.Archived);

and exception we are getting is

System.ArgumentException: GenericArguments[2], 'System.Collections.Generic.List`1[System.Collections.Generic.List`1[Program+Gift]]', on 'Void PopulateCollection[TCollection,TElement,TRelatedEntity](Int32, Microsoft.EntityFrameworkCore.Query.QueryContext, System.Data.Common.DbDataReader, Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryResultCoordinator, System.Func`3[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,System.Object[]], System.Func`3[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,System.Object[]], System.Func`3[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,System.Object[]], System.Collections.Generic.IReadOnlyList`1[Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer], System.Collections.Generic.IReadOnlyList`1[Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer], System.Collections.Generic.IReadOnlyList`1[Microsoft.EntityFrameworkCore.ChangeTracking.ValueComparer], System.Func`5[Microsoft.EntityFrameworkCore.Query.QueryContext,System.Data.Common.DbDataReader,Microsoft.EntityFrameworkCore.Query.Internal.ResultContext,Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryResultCoordinator,TRelatedEntity])' violates the constraint of type 'TRelatedEntity'.
 ---> System.Security.VerificationException: Method Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor+ShaperProcessingExpressionVisitor.PopulateCollection: type argument 'System.Collections.Generic.List`1[System.Collections.Generic.List`1[Program+Gift]]' violates the constraint of type parameter 'TRelatedEntity'.
   at System.RuntimeMethodHandle.GetStubIfNeeded(RuntimeMethodHandleInternal method, RuntimeType declaringType, RuntimeType[] methodInstantiation)
   at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
   --- End of inner exception stack trace ---
   at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, RuntimeType[] genericArguments, Exception e)
   at System.Reflection.RuntimeMethodInfo.MakeGenericMethod(Type[] methodInstantiation)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, LambdaExpression& relatedDataLoaders, Int32& collectionId)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at .(IQueryable , Action`1 , RelationalQueryContext& , Object& )
   at Z.EntityFramework.Extensions.EFPlusExtensions.EFPlusCreateCommand(IQueryable source, Action`1 action, RelationalQueryContext& queryContext, Object& compiledQuery)
   at Z.EntityFramework.Plus.BaseQueryFuture.CreateExecutorAndGetCommand(RelationalQueryContext& queryContext)
   at Z.EntityFramework.Plus.QueryFutureBatch.CreateCommandCombined()
   at Z.EntityFramework.Plus.QueryFutureBatch.ExecuteQueries()
   at Z.EntityFramework.Plus.QueryFutureEnumerable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Z.EntityFramework.Plus.QueryIncludeOptimizedParentQueryable`1.CreateEnumerable()
   at Z.EntityFramework.Plus.QueryIncludeOptimizedParentQueryable`1.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Program.Main()

3. Fiddle or Project

i reproduce the issue in dotnetfiddle and did some experiments,
https://dotnetfiddle.net/22qD0x
as i see it, if you use SelectMany() then do the Select() the problem is gone and i can use IncludeOptimized()

.IncludeOptimized(o => o.OfferItems.SelectMany(oi => oi.OfferItemScreenTenants).Select(oist=>oist.ScreenTenant))
this query works instead.

so the question is what is the best way to use IncludeOptimized for multilevel objects? Is this a correct usage?
thanks for the assistance

@JonathanMagnan JonathanMagnan self-assigned this Jan 24, 2022
@JonathanMagnan
Copy link
Member

Hello @cangunaydin ,

The best way has changed over time as some way that was working in EF Core 2 are no longer working in EF Core 3 and so on.

For example, another working way is the following LINQ:

var list = context.Orders
			.IncludeOptimized(x => x.Items.SelectMany(o=>o.OrderItemDetails))
			.IncludeOptimized(x => x.Items.SelectMany(o=>o.OrderItemDetails).SelectMany(y=>y.Gifts)).ToList();

Is it the best way? Look pretty much similar as the code you provided.

There is no "perfect" way, this is the same under the hood for our library. Everything depends on the EF Core version and what this version can support.

Best Regards,

Jon

@Prinsn
Copy link

Prinsn commented Jan 28, 2022

So the suggested migration here is to just change all instances of Select to SelectMany?

Is this a project level factor?

It seems like if IncludeOptomized(x => x.Select(z => z.IsCollectionType)) is always going to throw an exception, it should just be enforced?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants