Entity Framework Plus 라이브러리 및 특히 IncludeFilter 확장 메서드와 관련하여 이해하지 못하는 InvalidCastException을 제기하고 있습니다.
요약하자면, Project, Test 및 TestRun의 세 가지 엔티티가 있습니다.-각 프로젝트에는 테스트 모음이 있습니다. -각 테스트에는 TestRun 모음이 있습니다. 원하는 포함을 선택하는 옵션과 함께 데이터베이스에서 프로젝트를 검색하는 메소드를 구현하는 ProjectService 클래스가 있습니다. 이 방법의 코드는 다음과 같습니다 (여전히 동일한 예외를 생성하는 가장 작은 코드 조각과 비교할 수있는 다른 조각으로 제거했습니다).
private IQueryable<Project> NewQuery(ProjectIncludeOptions includes = ProjectIncludeOptions.NONE)
{
IQueryable<Project> query = base.NewQuery();
/* NO PROBLEM HERE: just left it for comparison. */
if (includes.HasFlag(ProjectIncludeOptions.DOMAINS))
{
query =
query
.IncludeFilter(p => p.TestDomains.Where(td => !td.IsArchived).Select(td => td.Children.Where(tdc => !tdc.IsArchived)))
.IncludeFilter(p => p.TestDomains.Where(td => !td.IsArchived).Select(td => td.Parent));
}
/* EXCEPTION CAUSED BY THE CODE BELOW */
if (includes.HasFlag(ProjectIncludeOptions.TESTS))
{
query =
query
/* In the below code, if I remove the Where clause, or use a non-calculated property in it, then the exception disappears. */
.IncludeFilter(p => p.Tests.Where(t => !t.IsArchived).Select(t => t.TestRuns));
}
return query;
}
테스트 클래스에서 IsArchived 속성의 구현은 다음과 같습니다.
[NotMapped]
public virtual bool IsArchived
{
get { return ArchivingDate.HasValue; }
set { ArchivingDate = value ? System.DateTime.Now : (System.DateTime?)null; }
}
그리고 실제로 InvalidCastException (SingleOrDefault 호출에서 오는)을 얻는 곳 :
Project project = NewQuery(includes).SingleOrDefault(p => p.Id == projectId);
완전한 예외 메시지는 다음과 같습니다.
System.InvalidCastException : ''System.String '유형의 객체를'System.Int32 '유형으로 캐스트 할 수 없습니다.'
오류가 발생했을 때 스택 추적 :
Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create (DbDataReader dataReader)에서 System.Data.SqlClient.SqlClient.SqlBuffer.get_Int32 ()에서 System.Data.SqlClient.SqlDataReader.GetInt32 (Int32 i)에서 lambda_method (Closure, DbDataReader)에서 Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable
1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func
Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Exec의 Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute에서1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func
31.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func
3 작업, 기능3 verifySucceeded) at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable
verifySucceeded) System.Linq.Lookup의 1.Enumerator.MoveNext () 2.CreateForJoin (2.CreateForJoin(IEnumerable
1 소스, Func2 keySelector, IEqualityComparer
1 비교기) System.Linq.Enumerable.JoinIterator [ TOuter, Tinner, TKey, TResult] (System.Linq.Enum에서 IEnumerable1 outer, IEnumerable
1 내부, Func2 outerKeySelector, Func
2 innerKeySelector, Func3 resultSelector, IEqualityComparer
1 비교기) + MoveNext () erable.GroupJoinIterator [TOuter, TInner, TKey, TResult] (IEnumerable1 outer, IEnumerable
1 inner, Func2 outerKeySelector, Func
2 innerKeySelector, Func3 resultSelector, IEqualityComparer
1 comparer) + MoveNext ()에서 System.Linq.Enumerable.SelectManyIterator [ TSource, TCollection, TResult] (IE3 resultSelector)+MoveNext() at System.Linq.Enumerable.SelectEnumerableIterator
Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities [TOut의 IEnumerable1 source, Func
2 collectionSelector, Func3 resultSelector)+MoveNext() at System.Linq.Enumerable.SelectEnumerableIterator
, TIn] (IEnumerable1 results, QueryContext queryContext, IList
1 entityTrackingInfos, IList1 entityAccessors)+MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor
1.EnumeratorExceptionInterceptor.MoveNext () Z.EntityFramework.Plus.QueryFutureEnumerable1.SetResult(IEnumerator
1 열거 자) 1.1.SetResult(DbDataReader reader) at Z.EntityFramework.Plus.QueryFutureBatch.ExecuteQueries() at Z.EntityFramework.Plus.QueryFutureValue
)에서1.SetResult(IEnumerator
1 열거 자1.SetResult(DbDataReader reader) at Z.EntityFramework.Plus.QueryFutureBatch.ExecuteQueries() at Z.EntityFramework.Plus.QueryFutureValue
1.get_Value () Z.EntityFramework.Plus.QueryIncludeFilterProvider1.Execute[TResult](Expression expression) at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable
1 소스, Expression`1 술어) Tresse.Service.Impl.ProjectService.Get (Int32 projectId, ProjectIncludeOptions 포함)
가장 당황스러운 것은 ProjectIncludeOptions.DOMAINS 부분을 사용할 때 예외가 발생하지 않는다는 것입니다.이 부분은 똑같은 방식으로 구현됩니다 (IsArchived 속성은 TestDomain 개체에서도 동일합니다).
또한 모든 엔티티 (Project, Test, TestRun 및 TestDomain) 에는 DateTime 속성이 있으며이 문제에서 중요한 역할을하는 것으로 보입니다. 실제로 Test 및 TestRun의 모든 DateTime 속성을 [NotMapped]
로 표시하면 (위와 같이 ProjectService의 모든 코드를 유지하면서) 예외가 사라집니다! 하나의 DateTime 속성 만 매핑 된 상태로두면 (어느쪽에 상관없이) 예외가 트리거됩니다. 그러나 TestDomain 및 위의 코드에는 아무런 문제가없는 것 같습니다.
그것은 당신에게 어떤 종류의 의미가 있습니까?
IncludeFilter 내부의 WHERE 절을 모두 제거 하여이 상황을 해결할 수 있었지만 (내 프로젝트에는 중요하지 않기 때문에) 적어도 무슨 일이 일어나고 있는지 이해하고 해결책을 가지고 기뻐할 것입니다. :)
이것이 정확히 문제인지 확실하지 않지만 IncludeFilter
의 목표는 쿼리를 생성하고 데이터베이스 측에서 필터링하는 것입니다.
그러나 IsArchived
속성은 매핑되지 않습니다. 이는 데이터베이스 측에서 실행될 쿼리를 생성 할 수 없음을 의미합니다 (클라이언트 측 평가로 인해 EF Core 2.x에서 가능할 수 있음).
필터링 부분을 모두 데이터베이스에서 수행 할 수 있는지 확인하십시오.
ArchivingDate
속성을 직접 사용하여 가능할 것으로 보입니다.