如何用 linq to EF 填充我的类对象?

Posted

技术标签:

【中文标题】如何用 linq to EF 填充我的类对象?【英文标题】:How to populate my class object with linq to EF? 【发布时间】:2020-08-30 18:28:04 【问题描述】:

我的班级,

  public class User
    
        public string Username
        
            get;
            set;
        
        public string Password
        
            get;
            set;
        
        public string [] Roles
        
            get;
            set;
        
    

我的查询是,

var innerJoinQuery =
                            (from u
                            in db.Users
                            join ur in db.UserRoles
                                on u.UserID equals ur.UserID
                            join r in db.Roles on ur.RoleID equals r.RoleID
                            select new 
                                Username=u.Username,
                                Password=u.Password,
                                RoleName = r.RoleName 
                            ).ToList();

上面查询中得到的数据是这样的,

username   password  RoleName
john        123       user
john        123       admin
john        123       super user
David       12345     super user
petter      123456    user

我想使用 Linq 在我的用户类对象中获取这些数据,

应该是这样的,

username   password  RoleName
john        123        "user", "admin", "super user" 
David       12345      "super user" 
petter      123456     "user"

我已经尝试了很多来自网络的例子,但我没有得到答案。

希望您的解决方案。

【问题讨论】:

【参考方案1】:

您正在寻找GroupBy 方法。不确定您的 ORM 是否支持它,但您始终可以在查询 db 后进行分组:

var innerJoinQuery =  (....)
    .ToList()
    .GroupBy(u => u.Username)
    .Select(g => new User
    
      Username=g.Key,
      Password=g.Select(i => i.Password).First(),// can be moved to grouping clause
      Roles = g.Select(i => i.RoleName).ToArray() 
    )      
    .ToList();

要尝试在对 db 的查询中执行 group by,您可以查看 this 问题,例如。

【讨论】:

我试过它给出了错误(方法'First'只能用作最终查询操作。考虑在这种情况下使用方法'FirstOrDefault'。) @Doc 抱歉,复制粘贴到 little,查询后添加 .ToList(),重试。 它现在可以工作了,我可以将此查询的结果移动到我的类“用户”对象 @Doc 查看更新。只需将最后一个选择从 new .. 更改为 new User 并更改 RoleNames 的一部分。 我了解您的查询我明白了我的意思是问,我有类似的对象 (private List UserList = new List();) 我如何添加 'innerJoinQuery ' 结果是“用户列表”?例如,我可以在 UserList 中添加类似 (UserList.Add(new Models.User Username = "Admin", Password = "12345", Roles = new string[] "Admin", "Super User", "User" );) 我在其他地方使用 UserList 变量。【参考方案2】:

您可以尝试以下使用子查询来选择所有角色名称的方法:

var innerJoinQuery = (
    from u in db.Users
    select new User
    
        Username = u.Username,
        Password = u.Password,
        Roles = (from ur in db.UserRoles
                 join r in db.Roles on ur.RoleID equals r.RoleID
                 where ur.UserID == u.UserID
                 select r.RoleName).ToArray()
    
).ToList();

或者,您可以使用group...by...into

var innerJoinQuery = (
    from u in db.Users
    join ur in db.UserRoles on u.UserID equals ur.UserID 
    join r in db.Roles on ur.RoleID equals r.RoleID
    group r by u into g
    select new User
    
        Username = g.Key.Username,
        Password = g.Key.Password,
        Roles = g.Select(c => c.RoleName).ToArray()
    
).ToList();

假设您的 ORM 支持这一点,它可能生成比聚合键然后从聚合组中进行子选择更好的查询。

如果 ORM 不能翻译 ToArray/ToList(Linq-To-SQL 不能),你可以

    User.Roles 的类型更改为IEnumerable<string> 而不是string[],然后删除上面的ToArray 调用,或者 选择匿名类型首先,具体化查询 (ToList),然后将结果重新投影到您的 User 类型中

#2 如下所示:

var innerJoinQuery = (
    from u in db.Users
    select new
    
        u.Username,
        u.Password,
        Roles = (from ur in db.UserRoles
                 join r in db.Roles on ur.RoleID equals r.RoleID
                 where ur.UserID == u.UserID
                 select r.RoleName)
    
).ToList();

var users = innerJoinQuery.Select(c => new User  
     UserName = c.UserName, 
     Password = c.Password,
     Roles = c.Roles.ToArray() 
); 

或者使用group...by 变体:

var innerJoinQuery= (
    from u in db.Users
    join ur in db.UserRoles on u.UserID equals ur.UserID 
    join r in db.Roles on ur.RoleID equals r.RoleID
    group r by u into g
    select new
    
        g.Key.Username,
        g.Key.Password,
        Roles = g.Select(c => c.RoleName)
    
).ToList();

var users = innerJoinQuery.Select(c => new User  
     UserName = c.UserName, 
     Password = c.Password,
     Roles = c.Roles.ToArray() 
); 

请注意,所有这些解决方案的优势在于它们在数据库中执行分组和/或子查询,而另一个答案是在内存中

【讨论】:

收到此错误(LINQ to Entities 无法识别方法 'System.String[] ToArray[String](System.Collections.Generic.IEnumerable`1[System.String])' 方法,以及此方法无法转换为商店表达式。)

以上是关于如何用 linq to EF 填充我的类对象?的主要内容,如果未能解决你的问题,请参考以下文章

Linq to EF 系统不支持异常 System.NotSupportedException

如何用另一个observable填充observable并返回observable

如何用对象列表过滤对象列表? [复制]

如何用空对象填充字符串数组?

用 LINQ to SQL 或 LINQ to EF 替换 NHibernate

LINQ To EF