Linq to Entities – SQL“IN”子句

在T-SQL中,您可以使用如下查询:

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

你将如何在LINQ to Entities查询中进行复制? 这甚至有可能吗?

您需要根据自己的想法来考虑问题。 如果在预定义的一组适用的用户权限中查找当前项目的用户权限,而不是在“in”中查询,那么你就需要一组预定义的用户权限(如果它包含当前项目的适用值)。 这与在.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:

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

在语法上,这看起来更复杂,而且您必须了解lambda表达式或代表的概念,才能真正弄清楚发生了什么,但正如您所看到的,这会将代码压缩到相当的程度。

这一切都归结于您的编码风格和偏好 – 我的三个例子都做同样的事情略有不同。

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

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

这应该足够你的目的。 它比较两个集合,并检查一个集合是否具有与其他集合中的值相匹配的值

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

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

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

我将在这方面去Inner Inner。 如果我将使用包含,它将重复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,它将搜索列表2中的每个List 1项目,这意味着迭代将发生49次!

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

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

我也尝试使用SQL-IN-like的方法 – 查询实体数据模型 。 我的方法是一个字符串生成器来组成一个大的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,则GUID前面总是有“GUID”。 如果不添加这个, ObjectQuery<T>.Where引发以下异常:

参数类型“Edm.Guid”和“Edm.String”与此操作不兼容,在等于表达式的第6行第14列。

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

马蒂亚斯

…期待下一个版本的.NET和实体框架,当一切变得更好。 🙂

BenAlabaster答案的另一种方法

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

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

当然这更“罗嗦”,写起来很痛苦,但是它的效果都是一样的。

所以,如果我们有一些实用的方法可以很容易地创建这些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的实际工作。

这是使这成为可能的管道功能:

 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 => 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

真的吗? 你们这些人从来没有用过

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