当从'VisitLambda'中调用时,重写类型为'System.Linq.Expressions.ParameterExpression'的节点必须返回一个非空值。

问题描述 投票:1回答:1

我有4个表。

1 - Users2 - UserRole3 - Role4 - AccessLevel。

我需要的是,当用户登录到应用程序时,访问级别列表将被发送到它。

我正在使用下面的代码来实现它。

                var userInfo = await Users.Where(x => x.Id == id)
                 .Select(x => new
                 {
                     UserDusplayName = x.Name + x.Family,
                     AccessLevel = x.UserRoles.FirstOrDefault().Role.AccessLevels.ToList()
                 })
                 .Select(v=>new UserInformationDto
                 {
                     DispayName=v.UserDusplayName,
                     AccessUnserInfos=v.AccessLevel.Select(x=>x.Access)
                 }).FirstOrDefaultAsync();

在我的数据库中这个id有一个AccessLevel。

然而,当我向这个ID发送一个请求时,它显示出以下内容。

当从'VisitLambda'调用时,重写一个类型为'System.Linq.Expressions.ParameterExpression'的节点必须返回一个相同类型的非空值。或者,覆盖'VisitLambda'并将其改为不访问该类型的子节点。

我的代码有什么问题? 我怎么能解决这个问题?

c# asp.net entity-framework asp.net-core entity-framework-core
1个回答
2
投票

我的代码有什么问题?

技术上的问题不是你的代码,这是一个有效的LINQ查询,但EF核心查询翻译器bugsshortcomings。

这里有两个结构

AccessLevel = x.UserRoles.FirstOrDefault().Role.AccessLevels.ToList()

导致EF Core翻译器出现问题。

首先是 ToList() 调用。虽然它在最终预测中得到了支持(Select),它会导致进一步的查询操作符(如 next Select 部分

v.AccessLevel.Select(x=>x.Access)

二是 FirstOrDefault() 此处

x.UserRoles.FirstOrDefault().Role.AccessLevels

即把一个序列转换为单项,然后再从中抽取子序列。

我怎样才能解决这个问题?

首先,删除 ToList() 或取消中间环节 Select. 第二,去除 FirstOrDefault() - 它没有意义,或者如果真的需要,用等价的集限制运算符来代替。Take(1). 使用集平运算符 SelectMany 以获得所需的子集。

AccessLevel = x.UserRoles.SelectMany(ur => ur.Role.AccessLevels)

应该可以解决当前的问题。


不相关,但由于在你的模型中,用户有许多角色,而角色有许多访问级别,这里的

AccessUnserInfos = v.AccessLevel.Select(x => x.Access)

你可能会得到重复的值,所以考虑应用 Distinct 经营者

AccessUnserInfos = v.AccessLevel.Select(x => x.Access).Distinct()
© www.soinside.com 2019 - 2024. All rights reserved.