0

我遇到了一个我不理解的 InvalidCastException,特别是与 Entity Framework Plus 库及其 IncludeFilter 扩展方法有关。

总而言之,我有 3 个实体:项目、测试和测试运行: - 每个项目都有一个测试集合;- 每个测试都有一组测试运行。我有一个 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 属性的实现(在 Test 类中)如下:

[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'类型。'

以及发生错误时的堆栈跟踪:

在 System.Data.SqlClient.SqlBuffer.get_Int32() 在 System.Data.SqlClient.SqlDataReader.GetInt32(Int32 i) 在 lambda_method(Closure , DbDataReader) 在 Microsoft.EntityFrameworkCore.Storage.Internal.TypedRelationalValueBufferFactory.Create(DbDataReader dataReader) 在Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable 1.Enumerator.BufferlessMoveNext(DbContext _, Boolean buffer) at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func3 操作,Func 3 verifySucceeded) at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable1.Enumerator.MoveNext() 在 System.Linq.Lookup 2.CreateForJoin(IEnumerable1 源,Func 2 keySelector, IEqualityComparer1 比较器)在 System.Linq.Enumerable.JoinIterator[TOuter,TInner,TKey,TResult] (IEnumerable 1 outer, IEnumerable1 内部,Func 2 outerKeySelector, Func2 innerKeySelector,Func 3 resultSelector, IEqualityComparer1 比较器)+MoveNext() at System.Linq.Enumerable.GroupJoinIterator[TOuter,TInner,TKey,TResult](IEnumerable 1 outer, IEnumerable1 内部,Func 2 outerKeySelector, Func2 innerKeySelector,Func3 resultSelector, IEqualityComparer1 个比较器)+MoveNext() 在 System.Linq.Enumerable.SelectManyIterator[TSource,TCollection,TResult](IEnumerable 1 source, Func2 collectionSelector, Func 3 resultSelector)+MoveNext() at System.Linq.Enumerable.SelectEnumerableIterator2.MoveNext() 在 Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider._TrackEntities[TOut,TIn] (IEnumerable 1 results, QueryContext queryContext, IList1 entityTrackingInfos,IList 1 entityAccessors)+MoveNext() at Microsoft.EntityFrameworkCore.Query.Internal.LinqOperatorProvider.ExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext() 在 Z.EntityFramework.Plus.QueryFutureEnumerable 1.SetResult(IEnumerator1 枚举器)在 Z.EntityFramework.Plus.QueryFutureEnumerable 1.SetResult(DbDataReader reader) at Z.EntityFramework.Plus.QueryFutureBatch.ExecuteQueries() at Z.EntityFramework.Plus.QueryFutureValue1.get_Value() 在 Z.EntityFramework.Plus.QueryIncludeFilterProvider 1.Execute[TResult](Expression expression) at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable1 源,表达式` 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 子句来解决这种情况(因为它对我的项目并不重要),但我很乐意至少了解正在发生的事情并有一个解决方案。:)

4

1 回答 1

0

我不确定这是否正是问题所在,但目标IncludeFilter是生成查询并在数据库端进行过滤。

但是,该IsArchived属性未映射。这意味着,不可能创建将在数据库端执行的查询(由于客户端评估,在 EF Core 2.x 中可能是可能的)。

确保过滤部分可以全部在数据库中完成。

ArchivingDate直接使用该属性似乎是可能的。

于 2020-03-11T11:41:38.587 回答