在T-SQL中,您可能有一个查询,例如:

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


如何在LINQ to Entities查询中复制该查询?可能吗?

#1 楼

您需要根据考虑的方式将其翻转。您不是要“输入”以在一组预定义的适用用户权限中查找当前项目的用户权限,而是要询问一组预定义的用户权限是否包含当前项目的适用值。这与在.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,您可以使用相同的方法语法将“ 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;
}


评论


也许我太快地无法将其标记为答案,但是在{“” Admin“,” User“,” Limited“}之后,VS2008不喜欢该代码。

– StevenMcD
09年5月13日在13:51

符合我的名字“ FailBoy”,我弄清楚了:P我放入了一个字符串[],然后使用它就可以了。谢谢!

– StevenMcD
09年5月13日在13:56

抱歉,我忘了重新创建匿名数组;)我修复了代码示例。很高兴您自己解决了。

– BenAlabaster
09年5月13日在14:07

如果问题是关于Linq-to-SQL或Linq的,那么这个答案是正确的。但是,由于它专门说“ Linq-to-Entities”,因此此答案不正确。 Linq-to-Entities不支持array.Contains。

– KristoferA
09年5月29日在7:04

@KristoferA-这对于早期版本的EF可能是正确的,但是对于EF4来说对我来说似乎还不错。

–德鲁·诺克斯(Drew Noakes)
2011年5月7日17:55

#2 楼

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

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


#3 楼

在这种情况下,我将参加内部联接。如果我使用过contains,即使有一个匹配项,它也会迭代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(); 


Contains的缺点

假设我有两个列表对象。

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


使用包含,它将搜索列表2中的每个列表1项目,这意味着迭代将发生49次! br />

评论


这完全忽略了将语句转换为SQL的事实。看这里。

– Gert Arnold
15年8月10日在22:23

#4 楼

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

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


#5 楼

我还尝试使用类似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前面总是带有单词“ GUID”。如果不添加此参数,则ObjectQuery<T>.Where会引发以下异常:


参数类型'Edm.Guid'和
'Edm.String'为此不兼容
操作,近似等于表达式,
第6行,第14列。


在MSDN论坛中发现此问题,可能对您有所帮助。

Matthias

...当一切变得更好时,期待下一个版本的.NET和Entity Framework。 :)

#6 楼

BenAlabaster的替代方法答案

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

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


当然,这更“罗word”和编写起来很麻烦,但是却能一样地工作。

所以,如果我们有一些实用的方法可以轻松地创建此类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)为所有值构建谓词表达式并对这些谓词进行OR运算,我不会尝试解释该方法。一起为完整的谓词创建表达式

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

#7 楼

实际示例:

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 楼

认真吗你们从未使用过

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


评论


-1在超过1000行的表中对20个或更多值进行尝试,您将很快看到接受的解决方案的优势。同样,向where语句添加任意数量的条件也不容易(例如,如果用户选择包括选项1和2,但不包括3)。

– Trisped
13年4月4日,0:55



好吧,我不需要任何疯狂的科学家之类的东西,这个答案就投我了,因为我需要一个AND和2个ORS var SamplePoints =(来自_db.tblPWS_WSF_SPID_ISN_Lookup.OrderBy(x => x.WSFStateCode)中的c)。 PWS == id &&((c.WSFStateCode.Substring(0,2)==“ SR”)||(c.WSFStateCode.Substring(0,2)==“ CH”))选择c).ToList() ;

–约翰
2014年11月3日,21:55

@Trisped-行数(1000)不会改变任何内容-还是我缺少任何内容?

– tymtam
2016年9月8日在22:08

@Tymski是的,行数很重要。行越多,计算就越多。与可能值的数量相同:Checks = NumValues * NumRows。因为这是M * N类型的计算,所以如果其中一个很小,那么执行每个必需检查的时间也将很小。我添加了约束,因此cjm30305将知道如何设置测试环境,以显示其解决方案不好的原因。

– Trisped
16-09-18在17:59

@Trisped您是说new [] {1,2,3} .Contains(x)进行的比较少于where(x == 1 || x == 2 || x == 3)的比较吗?

– tymtam
16-09-19在22:19