.net Linq到实体-SQL“;在;条款
在T-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有两种方法,一种使用查询语法,另一种使用方法语法。基本上
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-