We have contacts are stored via table-per-hierarchy, A contact is either a company or a person and a person always belongs to a company. Both inherit from contact.
EF Core 2.1 is used.
It looks like this
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; }
}
So far so good, what we now want to do is query the Sources
and include the contacts
(all of them, doesn't matter if person or company)
context.Contact.Include(c => c.Contact).FirstOrDefault();
This generates the following exception
Unable to cast object of type 'System.DateTime' to type 'System.Nullable``1[System.Guid]'.'
StackTrace
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
We already spent hours (more like days) trying to get to the root of the cause and a fix but to no avail.
EF Core somehow trips with our construct (maybe the construct itself is wrong)
If you disable LazyLoading the problem disappears.
Any idea what's the cause and what would fix this issue?
EDIT 2
I remove Sources
since they don't seem to be involved in the problem
EDIT 3 I added a sample repo
Just change the ConnectionString in DbContextFactory to your local path.
I was able to reproduce it with the provided repo in both EF Core 2.1.4 and 2.2 preview.
As you mentioned in the last update, the problem is somehow related to lazy loading (proxies?), because w/o UseLazyLoadingProxies()
the code works as expected (that's why I wasn't able to reproduce it initially).
Since this is apparently EF Core bug, there is nothing you can do than reporting it to the EF Core Issue Tracker and wait to be fixed. Unfortunately mist likely you won't get that included in the upcoming 2.2 release, but who knows, it's worth trying.