【问题标题】:LINQ query to fetch entities that include custom formatted field of associated entities?LINQ 查询以获取包含关联实体的自定义格式字段的实体?
【发布时间】:2014-02-06 23:06:21
【问题描述】:

LINQ 有点生疏 我想从给定用户的相关表中获取单个结果。请参阅下面的架构。 每个用户都有一个或多个角色。我想要一个用户名列表和一个自定义字符串,该字符串是他们的角色列表,格式为“Role1 - Role2 - Role3”,其中值是与该用户的 UserRole/Role 关联的 RoleNames。

Role
=====
RoleId
RoleCode
RoleName

UserRole
========
UserRoleId
RoleId
UserId

Users
======
UserId
UserName  

在 LINQpad 中对其进行测试,我可以获得用户名及其角色的列表,但我希望结果中的单个字段是所有用户角色的格式化字符串,而不是 RoleName,如上所述。

这就是我现在所拥有的。如何为每个用户构建角色列表?

from u in Users 
join ur in UserRoles on u.UserId equals ur.UserKey
join r in Roles on ur.RoleKey equals r.RoleId
select new { 
    u.UserId,
    u.UserName,
    r.RoleName
}

【问题讨论】:

    标签: entity-framework


    【解决方案1】:

    将 UserName 分组添加到您的 LINQ 查询中,并使用 string.Join 格式化由“-”分隔的角色。

    您可以在 LINQPad 中进行测试 -

    var Roles = new [] {new{RoleId=1,RoleCode="SU",RoleName="Super User"},new{RoleId=2,RoleCode="PU",RoleName="Power User"}};
    var Users = new [] {new{UserId=1,UserName="Bit Shift"},new{UserId=2,UserName="Edward"}};
    var UserRoles = new [] {new{UserRoleId=1,RoleId=1,UserId=1},new{UserRoleId=2,RoleId=2,UserId=1},new{UserRoleId=3,RoleId=2,UserId=2}};
    
    var userRoles = from u in Users 
    join ur in UserRoles on u.UserId equals ur.UserId
    join r in Roles on ur.RoleId equals r.RoleId
    select new
    { 
        u.UserId,
        u.UserName,
        r.RoleName
    }
    into userRole
    group userRole by userRole.UserName into userGroups
    select new{ UserName=userGroups.Key, Roles = string.Join(" - ", userGroups.Select(ug => ug.RoleName))};
    userRoles.Dump();
    

    更简洁的版本,结果中包含 UserId+UserName -

    var userRoles = from u in Users 
    join ur in UserRoles on u.UserId equals ur.UserId
    join r in Roles on ur.RoleId equals r.RoleId
    group r by u into userGroups
    select new{ User=userGroups.Key, Roles = string.Join(" - ", userGroups.Select(r => r.RoleName))};
    userRoles.Dump();
    

    在对 SQL 数据库执行时,您需要将查询分成两部分,因为 LINQ to SQL 不支持 String.Join,像这样 -

       var userRoleGroups = (from u in Users 
        join ur in UserRoles on u.UserId equals ur.UserId
        join r in Roles on ur.RoleId equals r.RoleId
        group r by u into userGroups select userGroups)
        .ToList(); // This causes SQL to be generated and executed
        var userRoles = from userGroups in userRoleGroups select(new{ User=userGroups.Key, Roles = string.Join(" - ", userGroups.Select(r => r.RoleName))});
        userRoles.Dump();
    

    或者按照您的建议尝试使用 Aggregate 而不是 String.Join,就像这样 -

    var userRoles = from u in Users 
    join ur in UserRoles on u.UserId equals ur.UserId
    join r in Roles on ur.RoleId equals r.RoleId
    group r by u into userGroups 
    select(new{ 
        User=userGroups.Key,
        Roles = userGroups.Select(s => s.RoleName).Aggregate((current, next) =>  current + " - " + next)});
    userRoles.Dump();
    

    【讨论】:

    • 当我切换到使用我的表而不是数组时,LINQpad 抱怨字符串连接 LINQ to Entities 无法识别方法 'System.String Join(System.String, System.Collections.Generic .IEnumerable`1[System.String])' 方法,一个...
    • OK,那是因为String.Join不能直接转成SQL。您需要分两步完成。我将修改答案以显示如何...
    • 或者可能使用 Aggregate() ?
    • 聚合是个好主意——我不知道 LINQ to SQL 是否会处理它——我也会补充一下,你能试试并告诉我它是否有效吗?
    • starange 错误无法将“LINQPad.Internal.LINQPadDbConnection”类型的对象转换为“System.Data.SqlClient.SqlConnection”类型。
    【解决方案2】:

    RoleNames 分组到UserNames 上,并使用 String.Join 获得所需的结果。

    from u in Users
    join ur in UserRoles on u.UserId equals ur.UserKey
    join r in Roles on ur.RoleKey equals r.RoleId
    group r.RoleName by u.UserName into grp
    select new {
      UserName = grp.Key,
      Roles = String.Join(" - ", grp)
    };
    

    这不会返回用户 ID。如果它们对结果很重要,则需要将代码更改为

    .... join as above
    group r.RoleName by new {u.UserId, u.UserName} into grp
    select new {
      grp.Key.UserName,
      grp.Key.UserId,
      Roles = String.Join(" - ", grp)
    };
    

    这将创建一个包含 UserId 和 UserName 的分组键,因此您可以在选择中使用它。

    【讨论】:

      猜你喜欢
      • 2013-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-23
      • 2023-03-26
      • 2011-03-25
      • 1970-01-01
      • 2021-01-31
      相关资源
      最近更新 更多