如何将两个连接表中的 IQueryable LINQ 结果返回到 List<string> 中?

Posted

技术标签:

【中文标题】如何将两个连接表中的 IQueryable LINQ 结果返回到 List<string> 中?【英文标题】:How to return IQueryable LINQ result from two joined tables into a List<string>? 【发布时间】:2021-03-23 21:34:55 【问题描述】:

这是一个附加问题:Entity Framework Core 5.0 How to convert LINQ for many-to-many join to use Intersection table for ASP.NET Membership

如何将RoleName 列的以下LINQ IQueryable 结果(来自两个连接表)的结果返回到List&lt;string&gt;

var queryResult = (this.DbContext.aspnet_UsersInRoles
                .Where(x => x.UserId == dpass.UserId)
                .Join(
                    this.DbContext.aspnet_Roles,
                    ur => ur.RoleId,
                    r => r.RoleId,
                    (ur, role) => new
                    
                        ur,
                        role
                    
                )
                .Select(x => new  x.ur.UserId, x.role.RoleName )
                );

更新 1

我需要值数组形式的List,以便我可以使用Contains() 方法。我需要搜索分配给UserId 的特定RoleNames。如果我在IQueryable上使用ToList(),那么数组结果的形式是:

RoleName = "admin"

角色名 = “用户”

我无法使用.Contains() 方法,因为我收到以下错误:

无法从 'string' 转换为 &lt;anonymous 类型:字符串 RoleName&gt;

似乎期望可以将查询结果分配给一个类。但是,一个不存在,因为我正在执行此操作。

更新 2

我需要列表中的queryResult,格式为:

“管理员”

“用户”

有了这个输出,我可以使用.Contains() 方法来执行多项检查。这用于确定Windows Forms 字段属性。因此,如果UserId 属于admin 角色,则表单启用某些复选框和单选按钮,而如果UserId 属于user 角色,则表单启用不同的复选框。这不是可用角色的详尽列表以及表单执行的检查。但是,重要的是需要在单独的 IF 语句中执行对 List 的多项检查。

目前,我可以使用queryResult 执行以下操作:

    获取RoleNames 的列表 通过检查特定的RoleNamequeryResult 执行单独的LINQ 查询 执行.Count() &gt; 0 检查以查看UserId 是否处于特定角色。

这似乎是一个丑陋的 hack,因为我有创建 1 + N 变量以通过 LINQ 检索并存储每个 RoleName 的中间步骤,然后检查 .Count() 是否大于零。我认为List 方法会更干净、更高效。如果可以的话。

var varUser = from d in queryResult
          where d.RoleName == "user"
          select new  d.RoleName ;

var varAdmin = from u in queryResult
                where u.RoleName == "admin"
                select new  u.RoleName ;

//... more declarations and LINQs ...

【问题讨论】:

我提供了我的问题的更新,提供了额外的上下文。 在计量化后使用GroupBy(x=> x.UserId),然后U可以在角色列表中搜索 使用导航属性,简单多了。 【参考方案1】:

简答: 仅选择 RoleName,并使用 SelectMany 而不是 Select

更好的答案

所以你有一个Roles 的表和一个Users 的表(我正在简化你的长标识符,不是问题的一部分,也不是太多的输入)。

RolesUsers 之间似乎存在多对多关系:每个Role 是零个或多个Users 的角色,每个User 都有零个或多个角色。

这种多对多关系是使用标准联结表实现的:UsersInRoles。这个联结表有两个外键:一个给用户,一个给角色。

您有一个 UserId,并且您似乎想要拥有此 ID 的用户的所有角色的所有名称。

这个怎么样:

int userId = ...

// Get the names of all Roles of the User with this Id
var namesOfRolesOfThisUser = dbContext.UsersInRoles

    // only the user with this Id:
    .Where(userInRole => userInRole.UserId == userId)

    // get the names of all Roles for this userInRole
    .SelectMany(userInRole => dbContext.Roles.Where(role => role.RoleId == userInRole.RoleId)
                                             .Select(role => role.RoleName));

简而言之:从 UsersInRoles 表中,仅保留属性 UserId 的值等于 userId 的那些 UsersInRoles。

从剩余的每个 UsersInRoles 中,选择具有与 UserInRole.RoleId 相等的 RoleId 的所有角色。从这些角色中获取 RoleName。

我使用SelectMany 来确保我得到一个字符串序列,而不是一系列字符串。

如果您怀疑有双重角色名称,请考虑在末尾附加 Distinct()

但我想加入!

有些人真的很喜欢自己做连接。

int userId = ...
var namesOfRolesOfThisUser = dbContext.UsersInRoles
    .Where(userInRole => userInRole.UserId == userId)
    .Join(dbContext.Roles,

    userInRole => userInRole.RoleId,  // from every UserInRole take the foreign key
    role => role.RoleId,              // from every Role take the primary key

    // when they match, take only the name of the Role
    (userInRole, role) => role.RoleName);

【讨论】:

简单、干净、优雅、高效。感谢您的解决方案和解释清楚的答案-您是一位绅士和学者。 Hat tip.【参考方案2】:

尝试使用 GroupBy()。注意,这种方法不支持直接IQueryable到SQL的转换。如果您尝试在.ToList() 之前调用GroupBy(),则会抛出错误。

在您的示例中,您可以这样做:在内存中选择一个列表,然后使用它:

var queryResult = (this.DbContext.aspnet_UsersInRoles
                       .Where(x => x.UserId == dpass.UserId)
                       .Join(this.DbContext.aspnet_Roles,
                                 ur => ur.RoleId,
                                 r => r.RoleId,
                                 (ur, role) => new  ur, role 
                                )
                       .Select(x => new  x.ur.UserId, x.role.RoleName )
                       .ToList()   // MATERIALIZE FIRST
                       .GroupBy(x => x.UserId)  //ADD THIS
                      );
        
queryResult.Contains(roleName=> roleName == "ROLE_TO_SEARCH")
var userId = queryResult.Key;

【讨论】:

答案不是我想要的。我已经更新了我的问题。

以上是关于如何将两个连接表中的 IQueryable LINQ 结果返回到 List<string> 中?的主要内容,如果未能解决你的问题,请参考以下文章

实体框架,如何将 IQueryable 与多个 where 转换为 SQL 一起使用?

如何连接两个表中的数据并将结果插入到新表中?

MySQL 将两个表中的记录与连接和不连接

使用内连接 SQLITE 从两个表中删除行

如何将 ODataQueryOptions<T> 应用于 IQueryable<X>

如何访问连接表中的数据?