【问题标题】:How do you add dynamic 'where' clauses to a linq query?如何将动态“where”子句添加到 linq 查询?
【发布时间】:2010-09-15 21:01:13
【问题描述】:

我有一个带有位掩码的用户表,其中包含用户的角色。下面的 linq 查询返回所有角色包括 1、4 或 16 的用户。

var users = from u in dc.Users
            where ((u.UserRolesBitmask & 1) == 1)
               || ((u.UserRolesBitmask & 4) == 4)
               || ((u.UserRolesBitmask & 16) == 16)
            select u;

我想将其重写为以下方法,以返回给定角色的所有用户,以便我可以重用它:

private List<User> GetUsersFromRoles(uint[] UserRoles) {}

关于如何动态构建我的查询的任何指示?谢谢

【问题讨论】:

    标签: c# linq dynamic


    【解决方案1】:

    您可以使用PredicateBuilder 类。

    PredicateBuilder 已经发布在LINQKit NuGet package

    LINQKit 是一套免费的 LINQ to SQL 和实体框架高级用户扩展。

    【讨论】:

    • 显然 PredicateBuilder 类有两个版本:网站上的源代码示例,这是 © Albahari & O'Reilly,保留所有权利;作为 LinqKit 的一部分,它“在许可的免费许可下,这意味着您可以随意修改它,并将其合并到您自己的商业或非商业软件中。”
    • LinqKit 可通过 NuGet 获得。
    【解决方案2】:

    假设您的 UserRoles 值本身就是位掩码,这样的事情会起作用吗?

    private List<User> GetUsersFromRoles(uint[] UserRoles) {
        uint roleMask = 0;
        for (var i = 0; i < UserRoles.Length;i++) roleMask= roleMask| UserRoles[i];
        // roleMasknow contains the OR'ed bitfields of the roles we're looking for
    
        return (from u in dc.Users where (u.UserRolesBitmask & roleMask) > 0) select u);
    }
    

    可能有一个很好的 LINQ 语法可以代替循环,但概念应该是相同的。

    【讨论】:

    • 这应该可以。而不是动态的 where 子句,您将其简化为一个。您提到的那个不错的 LINQ 语法可能是: uint roleMask = UserRoles.Aggregate(0, (combined, role) => combined | role);
    【解决方案3】:

    【讨论】:

      【解决方案4】:

      这是向您的 LINQ 查询添加可变数量的 where 子句的一种方法。 请注意,我没有触及您的位掩码逻辑,我只是​​关注多个 where

      // C#
      private List<User> GetUsersFromRoles(uint[] UserRoles)
      {
         var users = dc.Users;
      
         foreach (uint role in UserRoles)
         {
            users = users.Where(u => (u.UserRolesBitmask & role) == role);
         }
      
         return users.ToList();
      }
      

      编辑:实际上,这将 AND where 子句,而您想要 OR 它们。以下方法(内连接)在 LINQ to Objects 中有效,但不能使用 LINQ to SQL 转换为 SQL:

      var result = from user in Users
                   from role in UserRoles
                   where (user.UserRolesBitmask & role) == role
                   select user;
      

      【讨论】:

        【解决方案5】:

        这是怎么回事?它不是动态linq,而是完成目标。

        private List<User> GetUsersFromRoles(uint[] userRoles) 
        {
            List<User> users = new List<User>();
        
            foreach(uint userRole in UserRoles)
            {
                List<User> usersInRole = GetUsersFromRole(userRole);
                foreach(User user in usersInRole )
                {
                    users.Add(user);
                }
            }
            return users;
        }    
        
        private List<User> GetUsersFromRole(uint userRole) 
        {
            var users = from u in dc.Users
                    where ((u.UserRolesBitmask & UserRole) == UserRole)
                    select u;
        
            return users;    
        }
        

        【讨论】:

        • 另外,你需要在GetUsersFromRole中ToList
        【解决方案6】:
        private List<User> GetUsersFromRoles(uint UserRoles) {
          return from u in dc.Users            
                 where (u.UserRolesBitmask & UserRoles) != 0
                 select u;
        }
        

        UserRoles 参数应该作为位掩码提供,而不是数组。

        【讨论】:

        • 这将返回匹配所有给定角色的用户。他的方法返回匹配任何给定角色的用户。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多