Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net Linq到实体-SQL“;在;条款_.net_Linq_Linq To Entities_In Clause - Fatal编程技术网

.net Linq到实体-SQL“;在;条款

.net Linq到实体-SQL“;在;条款,.net,linq,linq-to-entities,in-clause,.net,Linq,Linq To Entities,In Clause,在T-SQL中,可以有如下查询: SELECT * FROM Users WHERE User_Rights IN ("Admin", "User", "Limited") 您将如何在LINQ到实体查询中复制它?甚至有可能吗?你需要从你对它的思考方式上彻底改变它。您不是通过“in”在预定义的适用用户权限集中查找当前项的用户权限,而是询问预定义的用户权限集是否包含当前项的适用值。这与在.NET的常规列表中查找项目的方式完全相同 使用LINQ有两种方法,一种使用查询语法,另一种使用方法语法。基本上

在T-SQL中,可以有如下查询:

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

您将如何在LINQ到实体查询中复制它?甚至有可能吗?

你需要从你对它的思考方式上彻底改变它。您不是通过“in”在预定义的适用用户权限集中查找当前项的用户权限,而是询问预定义的用户权限集是否包含当前项的适用值。这与在.NET的常规列表中查找项目的方式完全相同

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

查询语法:

方法语法:

在本例中,我个人的偏好可能是方法语法,因为我可以通过匿名调用执行foreach,而不是分配变量,如下所示:

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}
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());
    }
}
var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" || 
              Users.User_Rights == "Limited"
        select Users;
var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);
从语法上看,这看起来更复杂,您必须理解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;
}

我还尝试在类似的东西中使用SQL—对实体数据模型进行查询。我的方法是使用字符串生成器来编写一个大的OR表达式。那太难看了,但恐怕这是目前唯一的办法

现在看来是这样的:

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}
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());
    }
}
var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" || 
              Users.User_Rights == "Limited"
        select Users;
var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);
Queue productIds=新队列(Products.Select(p=>p.Key));
如果(productIds.Count>0)
{
StringBuilder sb=新的StringBuilder();
sb.AppendFormat(“{0}.ProductId=Guid\'{1}\'”,entities.Products.Name,ProductId.Dequeue());
而(productIds.Count>0)
{
sb.AppendFormat(“或{0}.ProductId=Guid\'{1}\'”,
entities.Products.Name,productIds.Dequeue());
}
}
在此上下文中使用GUID:如上所示,在查询字符串片段中,GUID ifself之前总是有“GUID”一词。如果不添加此项,
ObjectQuery.Where
引发以下异常:

参数类型为“Edm.Guid”和 “Edm.String”与此不兼容 运算,近似等于表达式, 第6行第14列

在MSDN论坛中发现这一点,可能有助于记住这一点

马蒂亚斯


。。。期待下一版本的.NET和实体框架,一切都会好起来的。:)

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

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

真的吗?你们从来没用过

where (t.MyTableId == 1 || t.MyTableId == 2 || t.MyTableId == 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(); 
包含的缺点 假设我有两个列表对象

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

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

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

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

BenAlabaster答案的另一种方法

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

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}
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());
    }
}
var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" || 
              Users.User_Rights == "Limited"
        select Users;
var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);
当然,这更“冗长”,写起来也很痛苦,但它仍然有效

所以,如果我们有一些实用的方法,可以很容易地创建这种LINQ表达式,我们就可以开始工作了

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

foreach(User u in users.Where(u => new [] { "Admin", "User", "Limited" }.Contains(u.User_Rights)))
{
    //Do stuff on each selected user;
}
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());
    }
}
var matches = from Users in people
        where Users.User_Rights == "Admin" ||
              Users.User_Rights == "Users" || 
              Users.User_Rights == "Limited"
        select Users;
var matches = ctx.People.Where(
        BuildOrExpression<People, string>(
           p => p.User_Rights, names
        )
);
但更重要的是,它实际上是针对.NET3.5SP1的

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

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);
}
公共静态表达式BuildOrExpression(
表达式值选择器,
IEnumerable值
)
{     
if(null==valueSelector)
抛出新ArgumentNullException(“valueSelector”);
if(null==值)
抛出新的ArgumentNullException(“值”);
ParameterExpression p=valueSelector.Parameters.Single();
如果(!values.Any())
返回e=>false;
变量等于值。选择(值=>
(表达式)Expression.Equal(
价值选择器。主体,
表达式.常数(
价值
类型(TValue)
)
)
);
var body=equals.Aggregate(
(累计,等于)=>表达式。或(累计,等于)
); 
返回表达式.Lambda(body,p);
}
我不打算解释这个方法,只是说它基本上使用valueSelector(即p=>p.User_Rights)为所有值构建一个谓词表达式,并将这些谓词组合在一起,为完整的谓词创建一个表达式

来源:

真实示例:

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;
var trackList=Model.TrackingHistory.GroupBy(x=>x.ShipmentStatusId)。选择(x=>x.Last()).Reverse();
List done_step1=新列表(){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()!=无效的

也许我太快了,没有把它标记为答案,但是在{“Admin”,“User”,“Limited”}VS2008之后,我没有得到一个.Contains。VS2008一点都不喜欢这个代码。我的名字是“FailBoy”,我想出来了:P我把它放进一个字符串[],然后使用它,它就成功了。谢谢抱歉,我忘记重新设置匿名数组;)我修复了我的代码示例。很高兴你自己解决了这个问题。如果这个问题是关于Linq到SQL或Linq的,那么这个答案是正确的。然而,由于它特别指出“Linq到实体”,这个答案是不正确的。Linq to实体(尚未)支持array.Contains。@KristoferA-