EF Core,table-per-hierarchy 和同一基础的引用实体 class 生成错误
EF Core, table-per-hierarchy and referencing entity of the same base class generates error
我们有联系人是通过 table-per-hierarchy 存储的,
联系人可以是公司或个人,个人始终属于公司。
都继承自 contact.
使用 EF Core 2.1。
看起来像这样
public abstract class Contact {
public virtual Guid Id { get; set; }
public virtual ICollection<Source> Sources{ set; get; } = new Collection<Source>();
}
public class Company : Contact {
public string CompanyName { set; get; }
public virtual ICollection<Person> People { set; get; } = new Collection<Person>();
}
public class Person: Contact {
public string Name { set; get; }
public DateTime Birthday { set; get; }
public virtual Company Company { set; get; }
}
到目前为止一切顺利,我们现在要做的是查询 Sources
并包含 contacts
(所有这些,不管是个人还是公司)
context.Contact.Include(c => c.Contact).FirstOrDefault();
这会产生以下异常
Unable to cast object of type 'System.DateTime' to type 'System.Nullable``1[System.Guid]'.'
堆栈跟踪
at lambda_method(Closure , ValueBuffer )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalMixedEntityEntry..ctor(IStateManager stateManager, IEntityType entityType, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryFactory.NewInternalEntityEntry(IStateManager stateManager, IEntityType entityType, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTrackingFromQuery(IEntityType baseEntityType, Object entity, ValueBuffer& valueBuffer, ISet`1 handledForeignKeys)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.StartTracking(Object entity, IEntityType entityType)
at lambda_method(Closure , QueryContext , AdSourceCrm , Object[] )
at Microsoft.EntityFrameworkCore.Query.Internal.IncludeCompiler._Include[TEntity](QueryContext queryContext, TEntity entity, Object[] included, Action`3 fixup)
at lambda_method(Closure , TransparentIdentifier`2 )
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at lambda_method(Closure )
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ResultEnumerable`1.GetEnumerator()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at EfTest.Program.Main(String[] args) in Program.cs:line 18
我们已经花了几个小时(更像是几天)试图找出原因并进行修复,但无济于事。
EF Core 以某种方式与我们的构造绊倒(也许构造本身是错误的)
如果禁用延迟加载,问题就会消失。
知道原因是什么以及如何解决这个问题吗?
编辑 2
我删除了 Sources
,因为他们似乎与问题无关
编辑 3
我添加了一个 sample repo
只需将 DbContextFactory 中的 ConnectionString 更改为您的本地路径。
我能够在 EF Core 2.1.4 和 2.2 预览版中使用提供的存储库重现它。
正如您在上次更新中提到的,问题在某种程度上与延迟加载(代理?)有关,因为 w/o UseLazyLoadingProxies()
代码按预期工作(这就是为什么我不能最初复制它)。
由于这显然是 EF Core 错误,除了将其报告给 EF Core Issue Tracker 并等待修复外,您别无他法。不幸的是,您可能不会在即将发布的 2.2 版本中获得它,但谁知道呢,它值得一试。
在我看来像是 Entity Framework 中的错误,但是您可以通过显式指定自动生成的属性来防止这种情况发生,例如将 CompanyId 属性 添加到 Person [=16] =]明确
这将防止 EF Core 将 Birthday 列错误地映射到 CompanyId 列
public class Person : Base
{
// ...
public virtual Company Company { set; get; }
public Guid? CompanyId { get; set; }
}
我们有联系人是通过 table-per-hierarchy 存储的, 联系人可以是公司或个人,个人始终属于公司。 都继承自 contact.
使用 EF Core 2.1。
看起来像这样
public abstract class Contact {
public virtual Guid Id { get; set; }
public virtual ICollection<Source> Sources{ set; get; } = new Collection<Source>();
}
public class Company : Contact {
public string CompanyName { set; get; }
public virtual ICollection<Person> People { set; get; } = new Collection<Person>();
}
public class Person: Contact {
public string Name { set; get; }
public DateTime Birthday { set; get; }
public virtual Company Company { set; get; }
}
到目前为止一切顺利,我们现在要做的是查询 Sources
并包含 contacts
(所有这些,不管是个人还是公司)
context.Contact.Include(c => c.Contact).FirstOrDefault();
这会产生以下异常
Unable to cast object of type 'System.DateTime' to type 'System.Nullable``1[System.Guid]'.'
堆栈跟踪
at lambda_method(Closure , ValueBuffer )
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalMixedEntityEntry..ctor(IStateManager stateManager, IEntityType entityType, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryFactory.NewInternalEntityEntry(IStateManager stateManager, IEntityType entityType, Object entity, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTrackingFromQuery(IEntityType baseEntityType, Object entity, ValueBuffer& valueBuffer, ISet`1 handledForeignKeys)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryBuffer.StartTracking(Object entity, IEntityType entityType)
at lambda_method(Closure , QueryContext , AdSourceCrm , Object[] )
at Microsoft.EntityFrameworkCore.Query.Internal.IncludeCompiler._Include[TEntity](QueryContext queryContext, TEntity entity, Object[] included, Action`3 fixup)
at lambda_method(Closure , TransparentIdentifier`2 )
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at lambda_method(Closure )
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ResultEnumerable`1.GetEnumerator()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn](IEnumerable`1 results, QueryContext queryContext, IList`1 entityTrackingInfos, IList`1 entityAccessors)+MoveNext()
at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass15_1`1.<CompileQueryCore>b__0(QueryContext qc)
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
at EfTest.Program.Main(String[] args) in Program.cs:line 18
我们已经花了几个小时(更像是几天)试图找出原因并进行修复,但无济于事。
EF Core 以某种方式与我们的构造绊倒(也许构造本身是错误的)
如果禁用延迟加载,问题就会消失。
知道原因是什么以及如何解决这个问题吗?
编辑 2
我删除了 Sources
,因为他们似乎与问题无关
编辑 3 我添加了一个 sample repo
只需将 DbContextFactory 中的 ConnectionString 更改为您的本地路径。
我能够在 EF Core 2.1.4 和 2.2 预览版中使用提供的存储库重现它。
正如您在上次更新中提到的,问题在某种程度上与延迟加载(代理?)有关,因为 w/o UseLazyLoadingProxies()
代码按预期工作(这就是为什么我不能最初复制它)。
由于这显然是 EF Core 错误,除了将其报告给 EF Core Issue Tracker 并等待修复外,您别无他法。不幸的是,您可能不会在即将发布的 2.2 版本中获得它,但谁知道呢,它值得一试。
在我看来像是 Entity Framework 中的错误,但是您可以通过显式指定自动生成的属性来防止这种情况发生,例如将 CompanyId 属性 添加到 Person [=16] =]明确
这将防止 EF Core 将 Birthday 列错误地映射到 CompanyId 列
public class Person : Base
{
// ...
public virtual Company Company { set; get; }
public Guid? CompanyId { get; set; }
}