zzzprojects/EntityFramework.DynamicFilters

EntityCommandCompilationException when using .Include() on class with subclass

jehhynes opened this issue · 2 comments

Description

When using DbSet.Include(x => x.Relationship) where Relationship is a type which has a subclass, we receive a EntityCommandCompilationException.

I've included the full exception below, and a test case which will run in the DynamicFiltersTests project (and fail with the following exception). This is using the latest codebase on master.

Exception

 Message: 
    Test method DynamicFiltersTests.NavigationTests.FilterIncludesWithSubclass threw exception: 
    System.Data.Entity.Core.EntityCommandCompilationException: An error occurred while preparing the command definition. See the inner exception for details. ---> System.ArgumentException: The specified navigation requires a navigation source of a type that is compatible with 'Transient.reference[DynamicFiltersTests.Employee]'.
    Parameter name: from
  Stack Trace: 
    at ArgumentValidation.RequireCompatibleType(DbExpression from, RelationshipEndMember end, Boolean allowAllRelationshipsInSameTypeHierarchy)
    at ArgumentValidation.ValidateNavigate(DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd, RelationshipType& relType, Boolean allowAllRelationshipsInSameTypeHierarchy)
    at DbExpressionBuilder.Navigate(DbExpression navigateFrom, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
    at DefaultExpressionVisitor.Visit(DbRelationshipNavigationExpression expression)
    at DbRelationshipNavigationExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
    at DefaultExpressionVisitor.VisitExpression(DbExpression expression)
    at DefaultExpressionVisitor.VisitList[TElement](IList`1 list, Func`2 map)
    at DefaultExpressionVisitor.VisitExpressionList(IList`1 list)
    at DefaultExpressionVisitor.Visit(DbNewInstanceExpression expression)
    at DynamicFilterQueryVisitorCSpace.Visit(DbNewInstanceExpression expression) in DynamicFilterQueryVisitorCSpace.cs line: 396
    at DbNewInstanceExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
    at DefaultExpressionVisitor.VisitExpression(DbExpression expression)
    at DefaultExpressionVisitor.VisitList[TElement](IList`1 list, Func`2 map)
    at DefaultExpressionVisitor.VisitExpressionList(IList`1 list)
    at DefaultExpressionVisitor.Visit(DbNewInstanceExpression expression)
    at DynamicFilterQueryVisitorCSpace.Visit(DbNewInstanceExpression expression) in DynamicFilterQueryVisitorCSpace.cs line: 396
    at DbNewInstanceExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
    at DefaultExpressionVisitor.VisitExpression(DbExpression expression)
    at DefaultExpressionVisitor.Visit(DbProjectExpression expression)
    at DynamicFilterQueryVisitorCSpace.Visit(DbProjectExpression expression) in DynamicFilterQueryVisitorCSpace.cs line: 418
    at DbProjectExpression.Accept[TResultType](DbExpressionVisitor`1 visitor)
    at DynamicFilterInterceptor.TreeCreated(DbCommandTreeInterceptionContext interceptionContext) in DynamicFilterInterceptor.cs line: 43
    at DbCommandTreeDispatcher.<Created>b__0(IDbCommandTreeInterceptor i, DbCommandTreeInterceptionContext c)
    at InternalDispatcher`1.Dispatch[TInterceptionContext,TResult](TResult result, TInterceptionContext interceptionContext, Action`2 intercept)
    at DbCommandTreeDispatcher.Created(DbCommandTree commandTree, DbInterceptionContext interceptionContext)
    at DbProviderServices.CreateCommandDefinition(DbCommandTree commandTree, DbInterceptionContext interceptionContext)
    at ObjectQueryExecutionPlanFactory.CreateCommandDefinition(ObjectContext context, DbQueryCommandTree tree)
    at  --- End of inner exception stack trace ---
    at ObjectQueryExecutionPlanFactory.CreateCommandDefinition(ObjectContext context, DbQueryCommandTree tree)
    at ObjectQueryExecutionPlanFactory.Prepare(ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, Boolean streaming, Span span, IEnumerable`1 compiledQueryParameters, AliasGenerator aliasGenerator)
    at EntitySqlQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
    at <>c__DisplayClass7.<GetResults>b__6()
    at ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
    at <>c__DisplayClass7.<GetResults>b__5()
    at DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
    at ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
    at IEnumerable<T>.GetEnumerator>b__0()
    at LazyEnumerator`1.MoveNext()
    at List`1.ctor(IEnumerable`1 collection)
    at Enumerable.ToList[TSource](IEnumerable`1 source)
    at NavigationTests.FilterIncludesWithSubclass() in NavigationTests.cs line: 21
Exception message:
Stack trace:

Fiddle or Project

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using EntityFramework.DynamicFilters;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DynamicFiltersTests
{
    [TestClass]
    public class NavigationTests
    {

        [TestMethod]
        public void FilterIncludesWithSubclass()
        {
            using (var context = new TestContext())
            {
                var list = context.Entity1s
                    .Include(x => x.User)
                    .ToList();
            }
        }
        
        #region Models

        public class Depot : PersistentObject, IFilterTenant
        {
            public virtual Tenant Tenant { get; set; }
        }

        public class Employee : UserAccount
        {
            public virtual Depot Depot { get; set; }
        }

        public class UserAccount : PersistentObject, IFilterTenant
        {
            public virtual Tenant Tenant { get; set; }
        }

        public class Entity1 : PersistentObject, IFilterTenant
        {
            [ForeignKey("Id")]
            public virtual UserAccount User { get; set; }
            public virtual Tenant Tenant { get; set; }
        }
        
        public class Tenant : PersistentObject
        {

        }

        public interface IPersistentObject
        {
            long Id { get; set; }
        }

        public abstract class PersistentObject : IPersistentObject
        {
            [Key]
            public virtual long Id { get; set; }
        }

        #endregion

        #region TestContext

        public class TestContext : TestContextBase<TestContext>, ITestContext
        {
            public long? FilterTenantId { get; set; }

            public DbSet<Tenant> Tenants { get; set; }
            public DbSet<UserAccount> UserAccounts { get; set; }
            public DbSet<Depot> Depots { get; set; }
            public DbSet<Entity1> Entity1s { get; set; }

            public override void Seed()
            {
                
            }

            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);

                modelBuilder.Filter<IFilterTenant, TestContext, long?>("TenantFilter", (o, id) => o.Tenant.Id == id, ctx => ctx.FilterTenantId);
            }
        }

        public interface IHasTenant
        {
            Tenant Tenant { get; set; }
        }
        public interface IFilterTenant : IHasTenant { }

        #endregion
    }
}


Further technical details

  • EF version: 6.1.3 (what's currently referenced on master)
  • EF DynamicFilters version: Current 'master' branch
  • Database Provider: mssqllocaldb (probably any provider)

Hello @jehhynes ,

Thank you for reporting, we will look at it if that's possible to support this.

Best Regards,

Jonathan


Performance Libraries
context.BulkInsert(list, options => options.BatchSize = 1000);
Entity Framework ExtensionsEntity Framework ClassicBulk OperationsDapper Plus

Runtime Evaluation
Eval.Execute("x + y", new {x = 1, y = 2}); // return 3
C# Eval FunctionSQL Eval Function

Hello @jehhynes ,

My developer and me tried to find a fix but unfortunately, both of us failed without any progression.

So we choose to leave the issue open but stop to work on it until we get another idea to try or another issue that gives us some hint that might lead to a resolution.