Linq to Entities - SQL“IN”子句

时间:2009-05-13 13:35:06

标签: .net linq linq-to-entities in-clause

在T-SQL中,您可以进行如下查询:

SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited")

您如何在LINQ to Entities查询中复制它?它甚至可能吗?

9 个答案:

答案 0 :(得分:340)

你需要根据你的思维方式把它转过来。如果它包含当前项目的适用值,您将询问一组预定义的用户权限,而不是“在”中查找当前项目在预定义的一组适用用户权限中的用户权限。这与在.NET中的常规列表中找到项目的方式完全相同。

使用LINQ有两种方法,一种使用查询语法,另一种使用方法语法。基本上,它们是相同的,可以根据您的偏好互换使用:

查询语法:

var selected = from u in users
               where new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights)
               select u

foreach(user u in selected)
{
    //Do your stuff on each selected user;
}

方法语法:

var selected = users.Where(u => new[] { "Admin", "User", "Limited" }.Contains(u.User_Rights));

foreach(user u in selected)
{
    //Do stuff on each selected user;
}

我在这个实例中的个人偏好可能是方法语法,因为我可以通过这样的匿名调用来代替分配变量:

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

从语法上看,这看起来更复杂,你必须理解lambda表达式或委托的概念才能真正弄清楚发生了什么,但正如你所看到的,这会使代码压缩很多。

这一切都取决于你的编码风格和偏好 - 我的三个例子都做了同样的事情。

另一种方法甚至不使用LINQ,您可以使用相同的方法语法将“where”替换为“FindAll”并获得相同的结果,这也适用于.NET 2.0:

foreach(User u in users.FindAll(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}

答案 1 :(得分:19)

这应该足以满足你的目的。它比较两个集合并检查一个集合的值是否与另一个集合中的值相匹配

fea_Features.Where(s => selectedFeatures.Contains(s.feaId))

答案 2 :(得分:9)

如果您使用的是VS2008 / .net 3.5,请参阅Alex James的提示#8: http://blogs.msdn.com/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx

否则只需使用array.Contains(someEntity.Member)方法。

答案 3 :(得分:6)

在这种情况下,我会选择Inner Join。如果我使用了包含,那么它会迭代6次,尽管事实上只有一个匹配。

var desiredNames = new[] { "Pankaj", "Garg" }; 

var people = new[]  
{  
    new { FirstName="Pankaj", Surname="Garg" },  
    new { FirstName="Marc", Surname="Gravell" },  
    new { FirstName="Jeff", Surname="Atwood" }  
}; 

var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered  select p.FirstName).ToList(); 

包含的缺点

假设我有两个列表对象。

List 1      List 2
  1           12
  2            7
  3            8
  4           98
  5            9
  6           10
  7            6

使用Contains,它将搜索List 2中的每个List 1项,这意味着迭代将发生49次!!!

答案 4 :(得分:5)

这可能是您可以直接使用LINQ扩展方法检查in子句

的方法
var result = _db.Companies.Where(c => _db.CurrentSessionVariableDetails.Select(s => s.CompanyId).Contains(c.Id)).ToList();

答案 5 :(得分:2)

我还尝试使用类似SQL-IN的东西 - 查询实体数据模型。我的方法是一个字符串构建器来组成一个大的OR表达式。这非常难看,但我担心这是现在唯一的出路。

现在好了,看起来像这样:

Queue<Guid> productIds = new Queue<Guid>(Products.Select(p => p.Key));
if(productIds.Count > 0)
{
    StringBuilder sb = new StringBuilder();
    sb.AppendFormat("{0}.ProductId = Guid\'{1}\'", entities.Products.Name, productIds.Dequeue());
    while(productIds.Count > 0)
    {
        sb.AppendFormat(" OR {0}.ProductId = Guid\'{1}\'",
          entities.Products.Name, productIds.Dequeue());
    }
}

在此上下文中使用GUID :正如您在上面所看到的,在查询字符串片段中的GUID ifself之前始终存在单词“GUID”。如果您不添加此项,ObjectQuery<T>.Where将引发以下异常:

  

参数类型'Edm.Guid'和   'Edm.String'与此不兼容   操作。,接近等于表达,   第6行,第14栏。

在MSDN论坛中找到这个,可能会有所帮助。

的Matthias

...期待下一版本的.NET和实体框架,当一切都变得更好。 :)

答案 6 :(得分:1)

BenAlabaster回答的另一种方法

首先,您可以像这样重写查询:

var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" || 
              Users.User_Rights == "Limited"
        select Users;

当然,这更像是罗嗦的&#39;写作很痛苦,但它的作用完全一样。

因此,如果我们有一些实用方法可以轻松创建这些LINQ表达式,那么我们就可以开展业务。

使用实用方法,您可以编写如下内容:

var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);

这构建了一个与以下内容具有相同效果的表达式:

var matches = from p in ctx.People
        where names.Contains(p.User_Rights)
        select p;

但更重要的是,它实际上适用于.NET 3.5 SP1。

以下是使这成为可能的管道功能:<​​/ p>

public static Expression<Func<TElement, bool>> BuildOrExpression<TElement, TValue>(
        Expression<Func<TElement, TValue>> valueSelector, 
        IEnumerable<TValue> values
    )
{     
    if (null == valueSelector) 
        throw new ArgumentNullException("valueSelector");

    if (null == values)
        throw new ArgumentNullException("values");  

    ParameterExpression p = valueSelector.Parameters.Single();

    if (!values.Any())   
        return e => false;

    var equals = values.Select(value =>
        (Expression)Expression.Equal(
             valueSelector.Body,
             Expression.Constant(
                 value,
                 typeof(TValue)
             )
        )
    );
   var body = equals.Aggregate<Expression>(
            (accumulate, equal) => Expression.Or(accumulate, equal)
    ); 

   return Expression.Lambda<Func<TElement, bool>>(body, p);
}

我不打算尝试解释这个方法,除了说它基本上使用valueSelector为所有值构建谓词表达式(即p =&gt; p.User_Rights)并将这些谓词组合在一起为完整谓词创建表达式

来源:http://blogs.msdn.com/b/alexj/archive/2009/03/26/tip-8-writing-where-in-style-queries-using-linq-to-entities.aspx

答案 7 :(得分:0)

真实示例:

var trackList = Model.TrackingHistory.GroupBy(x => x.ShipmentStatusId).Select(x => x.Last()).Reverse();
List<int> done_step1 = new List<int>() {2,3,4,5,6,7,8,9,10,11,14,18,21,22,23,24,25,26 };
bool isExists = trackList.Where(x => done_step1.Contains(x.ShipmentStatusId.Value)).FirstOrDefault() != null;

答案 8 :(得分:-12)

真的?你们从未使用过

where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 3)