Linq Select 不会在 EF Core 中检索超过 3 个子级别的对象数据
Linq Select wont retrieve beyond 3 sub levels of object data in EF Core
我已经用虚构的名称替换了对象名称,以免有人质疑我的这个数据库的业务案例很奇怪 :)
如果我将下面代码中的 FavouriteBook.Name 替换为 FavouriteBookId.ToString() 我会恢复正常,因为如果有用户,总会有一本最喜欢的书。
如果商店没有用户,以下代码也有效。但是一旦有用户.. 如果它比 Profile 更深任何级别,它似乎不想获取数据。
(Profile是user的强制对象,favorite book是Profile的强制对象。"Name"是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 方法 returns 错误请求错误:
- $exception {System.NullReferenceException: Object reference not set to an instance of an object. at lambda_method(Closure , Object[] )
at
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor.ExecuteAsync[T](IReadOnlyList
1
taskFactories, Func
2 selector) at
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable2.AsyncSelectEnumerator.MoveNext(CancellationToken
cancellationToken) at
Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor
1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken
cancellationToken) at
System.Linq.AsyncEnumerable.Aggregate[TSource,TAccumulate,TResult](IAsyncEnumerable1
source, TAccumulate seed, Func
3 accumulator, Func2 resultSelector,
CancellationToken cancellationToken) at {namespace of repo
method}(Int32 RecId, List
1 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: An exception occurred in
the database while iterating the results of a query for context type
'{namespace of my context}'.
System.NullReferenceException: Object reference not set to an instance
of an object. at lambda_method(Closure , Object[] ) at
Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor._ExecuteAsync[T](IReadOnlyList1
taskFactories, Func
2 selector) at
Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable2.AsyncSelectEnumerator.MoveNext(CancellationToken
cancellationToken) at
Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor
1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken
cancellationToken)
我正在使用 .NET Core/EF core/SQL 服务器 13.0。
您引用的实体似乎没有按需加载。您是否正确定义了延迟加载?
您可以通过调用
直接加载这些引用
.Include()
所以你需要改变
_context.Shops.Include(s=> s.User.Profile.FavouriteBook)
然后你就可以做剩下的过滤和投影了。
我不能确切地说出问题所在,因为这取决于使用的 EF Core 版本 - EF Core 查询转换/处理仍然不稳定。如果您包含 EF Core 日志记录输出(如已执行 SQL 查询、客户端评估警告(如果有)等),那就太好了。
但是一般的表达方式是这样的
y.User.FirstOrDefault(x => x.UserId == y.UserId).Profile.FavouriteBook.Name
总是可疑 - 正确执行完全取决于查询提供程序对 FirstOrDefault
返回的潜在 null
"object" 属性的实现。 LINQ to Objects 肯定会抛出 NRE。如果使用服务器评估,EF Core 应该能够通过返回 null
来处理它,但根据异常情况,它不是由于翻译或 client/mixed 结果评估。
话虽如此,我个人会尝试使用包含 Where
+ Select
的等效 "natural" 方法返回 null
最终值final 属性 和 then 应用 FirstOrDefault
,例如
UserFavouriteBook = y.User
.Where(x => x.UserId == y.UserId)
.Select(x => x.Profile.FavouriteBook.Name)
.FirstOrDefault() ?? "N/A"
我已经用虚构的名称替换了对象名称,以免有人质疑我的这个数据库的业务案例很奇怪 :)
如果我将下面代码中的 FavouriteBook.Name 替换为 FavouriteBookId.ToString() 我会恢复正常,因为如果有用户,总会有一本最喜欢的书。 如果商店没有用户,以下代码也有效。但是一旦有用户.. 如果它比 Profile 更深任何级别,它似乎不想获取数据。
(Profile是user的强制对象,favorite book是Profile的强制对象。"Name"是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 方法 returns 错误请求错误:
- $exception {System.NullReferenceException: Object reference not set to an instance of an object. at lambda_method(Closure , Object[] ) at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor.ExecuteAsync[T](IReadOnlyList
1 taskFactories, Func
2 selector) at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable2.AsyncSelectEnumerator.MoveNext(CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor
1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken) at System.Linq.AsyncEnumerable.Aggregate[TSource,TAccumulate,TResult](IAsyncEnumerable1 source, TAccumulate seed, Func
3 accumulator, Func2 resultSelector, CancellationToken cancellationToken) at {namespace of repo method}(Int32 RecId, List
1 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: An exception occurred in the database while iterating the results of a query for context type '{namespace of my context}'. System.NullReferenceException: Object reference not set to an instance of an object. at lambda_method(Closure , Object[] ) at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.TaskLiftingExpressionVisitor._ExecuteAsync[T](IReadOnlyList
1 taskFactories, Func
2 selector) at Microsoft.EntityFrameworkCore.Query.EntityQueryModelVisitor.AsyncSelectEnumerable2.AsyncSelectEnumerator.MoveNext(CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor
1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)
我正在使用 .NET Core/EF core/SQL 服务器 13.0。
您引用的实体似乎没有按需加载。您是否正确定义了延迟加载?
您可以通过调用
直接加载这些引用.Include()
所以你需要改变
_context.Shops.Include(s=> s.User.Profile.FavouriteBook)
然后你就可以做剩下的过滤和投影了。
我不能确切地说出问题所在,因为这取决于使用的 EF Core 版本 - EF Core 查询转换/处理仍然不稳定。如果您包含 EF Core 日志记录输出(如已执行 SQL 查询、客户端评估警告(如果有)等),那就太好了。
但是一般的表达方式是这样的
y.User.FirstOrDefault(x => x.UserId == y.UserId).Profile.FavouriteBook.Name
总是可疑 - 正确执行完全取决于查询提供程序对 FirstOrDefault
返回的潜在 null
"object" 属性的实现。 LINQ to Objects 肯定会抛出 NRE。如果使用服务器评估,EF Core 应该能够通过返回 null
来处理它,但根据异常情况,它不是由于翻译或 client/mixed 结果评估。
话虽如此,我个人会尝试使用包含 Where
+ Select
的等效 "natural" 方法返回 null
最终值final 属性 和 then 应用 FirstOrDefault
,例如
UserFavouriteBook = y.User
.Where(x => x.UserId == y.UserId)
.Select(x => x.Profile.FavouriteBook.Name)
.FirstOrDefault() ?? "N/A"