Efcore: Cosmos Owned Entity Collection with multiple collections and Lazy Loaders throw ArgumentException/ TargetInvocationException

Created on 13 Dec 2019  路  9Comments  路  Source: dotnet/efcore

Using EF Core with CosmosDB provider and Lazy Loaders.

Collections of owned entities fail with exception when attempting to access the entities - the lazy loader throws and I think it's a type and reflection issue.

Steps to reproduce

I've created a small asp.net core project + repo. There are instructions in the readme.

https://github.com/xtellurian/efcore-cosmos-ownedentitycollectionrepro

Exception

System.ArgumentException: Expression of type 'System.Collections.Generic.ICollection`1[src.Model.Building]' cannot be used for return type 'src.Model.Building'
   at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters, String paramName)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, Boolean tailCall, IEnumerable`1 parameters)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, ParameterExpression[] parameters)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.Select[TSource,TResult](IQueryable`1 source, String propertyName)
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
 ---> System.ArgumentException: Expression of type 'System.Collections.Generic.ICollection`1[src.Model.Building]' cannot be used for return type 'src.Model.Building'
   at System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 parameters, String paramName)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 parameters)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, Boolean tailCall, IEnumerable`1 parameters)
   at System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, ParameterExpression[] parameters)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.Select[TSource,TResult](IQueryable`1 source, String propertyName)
   --- End of inner exception stack trace ---
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.BuildQueryRoot(IEntityType ownerOrDefiningEntityType, IEntityType entityType, String navigationName)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.BuildQueryRoot(IEntityType entityType)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.BuildQueryRoot(IEntityType ownerOrDefiningEntityType, IEntityType entityType, String navigationName)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.BuildQueryRoot(IEntityType entityType)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1..ctor(IStateManager stateManager, IDbSetSource setSource, IDbSetCache setCache, IEntityType entityType)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinderSource.<>c__3`1.<CreateConstructor>b__3_0(IStateManager s, IDbSetSource src, IDbSetCache c, IEntityType t)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinderSource.Create(IStateManager stateManager, IDbSetSource setSource, IDbSetCache setCache, IEntityType type)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinderFactory.Create(IEntityType type)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.CreateEntityFinder(IEntityType entityType)
   at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.get_TargetFinder()
   at Microsoft.EntityFrameworkCore.ChangeTracking.NavigationEntry.Load()
   at Microsoft.EntityFrameworkCore.ChangeTracking.CollectionEntry.Load()
   at Microsoft.EntityFrameworkCore.Internal.LazyLoader.Load(Object entity, String navigationName)
   at Microsoft.EntityFrameworkCore.Proxies.Internal.LazyLoadingInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.BuildingProxy.get_Devices()
   at Newtonsoft.Json.Serialization.ExpressionValueProvider.GetValue(Object target)

Further technical details

EF Core version: 3.1.0
Database provider: Cosmos
Target framework: dotnet core 3.1
Operating system: Mac OS
IDE: VS Code

area-cosmos customer-reported punted-for-5.0 type-bug verify-fixed

All 9 comments

@xtellurian Is there a reason you need to use lazy-loading given that the navigations are all configured to use owned collections, which are eagerly loaded?

@ajcvickers this is just a sample project meant to illustrate the bug, not my real code-base.

I'm using relationships between regular EF entities, which are lazy-loaded. Lazy-loading is an "all-or-nothing" option, even with owned collections.

Note for triage: this repros on Cosmos but the same model works correctly when using SQL Server. This indicates that it is a Cosmos-specific issue and not just an owned collection issue.

@xtellurian We will look into fixing this. For now, the workaround is to not use lazy-loading with Cosmos.

@ajcvickers thanks, although refactoring my application to not use lazy-loading is quite a lot of work.

@ajcvickers is it possible to get an estimate of when this may be fixed? I'm trying to plan future work, and want to understand whether I need to build a workaround.

Cheers,

@xtellurian Not sooner than November (unless you're ok using previews)

tldr; you can't solve this problem with inheritance and a single collection.

I'm considering various workarounds, and it looks like merging the two owned collections isn't an option due to the limitation on inheritance hierarchies for owned entity types.

https://docs.microsoft.com/en-us/ef/core/modeling/owned-entities#limitations

We solved this for general case as #22084
Leaving this open to verify for cosmos scenario.

Was this page helpful?
0 / 5 - 0 ratings