首页 > 解决方案 > Linq Select 不会在 EF Core 中检索超过 3 个子级别的对象数据

问题描述

在有人质疑我对这个数据库的商业案例的奇怪之处之前,我已经用虚构的对象名称替换了对象名称 :)

如果我将下面代码中的 FavouriteBook.Name 替换为 FavouriteBookId.ToString() 我会得到很好的恢复,因为如果有用户,总会有一本最喜欢的书。如果商店没有用户,以下代码也适用。但是一旦有用户.. 如果数据比 Profile 更深,它似乎不想获取数据。

(个人资料是用户的强制对象,喜欢的书是个人资料的强制对象。“名称”是FavouriteBook对象上的字符串属性)

var ret = _context.Shops.Where(x => x.ShopId == shopId);
var selected= ret.Select(y => new UserSummaryRow //my DTO
{
    //…other properties being set have been trimmed
    UserFavouriteBook = 
      y.User.FirstOrDefault(x => x.UserId == y.UserId) == null ? "N/A" 
    : y.User.FirstOrDefault(x => x.UserId == y.UserId).Profile.FavouriteBook.Name

});
var summary = await selected.ToListAsync();
return summary;

当执行带有“await”的行时,调用此存储库方法的 api 方法返回错误请求并显示错误:

  • $exception {System.NullReferenceException:对象引用未设置为对象的实例。在 Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor 的 lambda_method(Closure, Object[])。Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable 处的ExecuteAsync[T](IReadOnlyList 1 taskFactories, Func2 选择器) 2.AsyncSelectEnumerator.MoveNext(CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptorSystem.Linq.AsyncEnumerable.Aggregate 处的 1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancelToken) [TSource,TAccumulate,TResult](IAsyncEnumerable 1 source, TAccumulate seed, Func3 累加器, Func 2 resultSelector, CancellationToken cancellationToken) at {namespace of repo method}(Int32 RecId, List1 statuses) in .cs:line 2104 at {namespace on api controller method}(String dtoString) in C:\Dev}path to repo}:line 608} System.NullReferenceException

输出显示:

Microsoft.EntityFrameworkCore.Query:Error:在迭代上下文类型“{我的上下文的命名空间}”的查询结果时,数据库中发生异常。System.NullReferenceException:对象引用未设置为对象的实例。1 taskFactories, Func在Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable 2.AsyncSelectEnumerator.MoveNext(CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancelToken )的 lambda_method(Closure , Object[] )

我正在使用 .NET Core / EF Core / SQL Server 13.0。

标签: .netentity-frameworklinq.net-coreef-core-2.0

解决方案


我不能确切地说出问题所在,因为它取决于使用的 EF Core 版本 - EF Core 查询翻译/处理仍然不稳定。如果您包含 EF Core 日志记录输出(如执行的 SQL 查询、客户端评估警告(如果有)等),那就太好了。

但一般来说像这样的表达

y.User.FirstOrDefault(x => x.UserId == y.UserId).Profile.FavouriteBook.Name

总是可疑的——正确的执行完全取决于查询提供者对nullFirstOrDefault. LINQ to Objects 肯定会抛出 NRE。如果使用服务器评估,EF Core 应该能够通过返回来处理它null,但根据异常,它不是由于翻译或客户端/混合结果评估。

话虽如此,我个人会尝试使用等效的“自然”方式返回null最终值,方法是使用包含最终属性的Where+然后应用,例如SelectFirstOrDefault

UserFavouriteBook = y.User
    .Where(x => x.UserId == y.UserId)
    .Select(x => x.Profile.FavouriteBook.Name)
    .FirstOrDefault() ?? "N/A" 

推荐阅读