【问题标题】:How can I determine if an entity collection contains one of several possible values?如何确定实体集合是否包含多个可能值之一?
【发布时间】:2009-07-24 18:54:34
【问题描述】:

使用 .Net Entity Framework 和 Linq,我在寻找最佳(即最容易阅读/理解)方法来实现搜索实体集合是否包含多个可能值中的任何一个时遇到了问题。

考虑一个基本的成员资格/角色实现,其中用户有一个角色集合。

“此用户是否具有以下任何角色:role1、role2 或 role3?”的“最佳”方式是什么?

我可以用 1 个角色来检查,如下所示:

if myUser.Roles.Contains(role1) { // do something }

是否有一种简单的方法可以向此检查添加更多角色?

【问题讨论】:

    标签: c# linq entity-framework


    【解决方案1】:

    如果角色列表在编译时已知,那么您可以执行以下操作:

    if (myUser.Roles.Count(r => r.Id == role1.Id || r.Id == role2.Id) > 0)
    { 
        // do something 
    }
    

    如果您想检查一个动态构建的角色列表,它会变得更加棘手。让我知道这是否是您需要的。

    EDITEDAny() 更改为 Count() > 0 -- 我记错了 L2E 与 L2SQL 中的这个限制。

    【讨论】:

    • .Any() 在 Linq to Entities 中似乎无效......但这看起来像是我想要完成的......
    【解决方案2】:

    编辑:我刚刚进行了一些测试。有趣的是,IN 与 OR 的性能完全相同,所以除了 SQL 看起来很丑之外,它们的性能几乎相同。 我已经编辑了我的回复以反映这一点。

    EF 本身不支持“IN”样式查询(目前) 我相信你想要完成的事情已经被覆盖了here

    您可以通过以下方式获取匹配的实体:

            var roleNamesToMatch = {"Admin","Manager","Associate"};
            var expression = BuildOrExpression<Role, name>(r => r.Name, roleNamesToMatch);
            var matchingRoles = context.RoleSet.Where(expression);
    

    基于表达式树,EF 将创建如下所示的 SQL:

    select r.ID,r.Name from t_Role where r.Name = 'Admin' OR r.Name = 'Manager' 
    OR r.Name = 'Associate'
    

    而不是人们通常所期望的

    select r.ID,r.Name from t_Role where r.Name in ('Admin','Manager','Associate')
    

    【讨论】:

    • IN(...) 和一系列 OR 语句之间没有 SQL 性能差异。在查询计划方面,它们是相同的。
    【解决方案3】:

    使用Count() 会做不必要的工作。您可以将角色 ID 检查与Any() 方法结合起来进行存在性检查:

    if(myUser.Roles.Any(role => role.Id == role1.Id || role.Id == role2.Id)
    {
        // ...
    }
    

    【讨论】:

      【解决方案4】:
      var checkForRoles = new Role[] { Role1, Role2, Role3 };
      
      if (myUser.Roles.Any(r => search.Contains(checkForRoles))) {
         //the user is in one of the roles. 
      }
      

      【讨论】:

      • 实体框架不支持 Contains(),并且无论如何 Contains() 不采用数组或 IEnumerable 作为其参数——所以我不确定这是什么意思去做。
      • 你是对的。我不知道 EF 不支持包含。我正在寻找一种方法来测试一个动态列表。今天早上我在做一些测试,EF 似乎也不能与 Intersect 一起工作 - 我已经被 L2S 宠坏了。
      • 在 EF 中实现 Contains 样式行为的唯一方法是使用 ExpressionTree
      • @BenM 至少从 v4 开始,它确实如此——但不是你所期望的那样。它会起作用,但您必须为您的实体实现 .Equals() 方法(例如,在部分类中)。而且,这可能是一种过于宽泛和昂贵的方法,因为有意义的.Equals() 方法将比较每个字段和关系……对于每个对象,如果您尝试使用.Contains()
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-31
      相关资源
      最近更新 更多