.net LINQ 中的动态 where 子句 - 列名在运行时可用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/234439/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dynamic where clause in LINQ - with column names available at runtime
提问by sandesh247
Disclaimer: I've solved the problem using Expressions from System.Linq.Expressions, but I'm still looking for a better/easier way.
免责声明:我已经使用 System.Linq.Expressions 中的表达式解决了这个问题,但我仍在寻找更好/更简单的方法。
Consider the following situation :
考虑以下情况:
var query =
from c in db.Customers
where (c.ContactFirstName.Contains("BlackListed") ||
c.ContactLastName.Contains("BlackListed") ||
c.Address.Contains("BlackListed"))
select c;
The columns/attributes that need to be checked against the blacklisted term are only available to me at runtime. How do I generate this dynamic where clause?
需要对照列入黑名单的术语检查的列/属性仅在运行时对我可用。如何生成这个动态 where 子句?
An additional complication is that the Queryable collection (db.Customers above) is typed to a Queryable of the base class of 'Customer' (say 'Person'), and therefore writing c.Address as above is not an option.
一个额外的复杂问题是 Queryable 集合(上面的 db.Customers)被输入到 'Customer' 的基类(比如 'Person')的 Queryable 中,因此像上面那样写 c.Address 不是一个选项。
回答by Aaron Powell
@Geoff has the best option, justing Dynamic LINQ.
@Geoff 有最好的选择,只是动态 LINQ。
If you want to go the way of building queries at runtime using Lambda though I'd recomment that you use the PredicateBuilder (http://www.albahari.com/nutshell/predicatebuilder.aspx) and have something such as this:
如果您想在运行时使用 Lambda 构建查询,尽管我建议您使用 PredicateBuilder ( http://www.albahari.com/nutshell/predicatebuilder.aspx) 并具有如下内容:
Expression<Fun<T,bool>> pred = null; //delcare the predicate to start with. Note - I don't know your type so I just used T
if(blacklistFirstName){
pred = p => p.ContactFirstName.Contains("Blacklisted");
}
if(blacklistLastName){
if(pred == null){
pred = p => p.ContactLastName.Contains("Blacklisted"); //if it doesn't exist just assign it
}else{
pred = pred.And(p => p.ContactLastName.Contains("Blacklisted"); //otherwise we add it as an And clause
}
}
And so on for all the columns you want to include. When you get to your query you just need something like this:
对要包含的所有列依此类推。当您进行查询时,您只需要这样的东西:
var results = db.Customers.Where(pred).Select(c => c);
I've used this to do building of LINQ for searching where there are about 20 different options and it produces really good SQL.
我用它来构建 LINQ 以搜索大约有 20 个不同选项的地方,它产生了非常好的 SQL。
回答by James Curran
var query = from C in db.Customers select c;
if (seachFirstName)
query = query.Where(c=>c.ContactFirstname.Contains("Blacklisted"));
if (seachLastName)
query = query.Where(c=>c.ContactLastname.Contains("Blacklisted"));
if (seachAddress)
query = query.Where(c=>c.Address.Contains("Blacklisted"));
Note that they aren't mutually exclusive.
请注意,它们并不相互排斥。
回答by timothy
You can turn your where clauses on and off using some logic expressions.
您可以使用一些逻辑表达式打开和关闭 where 子句。
//Turn on all where clauses
bool ignoreFirstName = false;
bool ignoreLastName = false;;
bool ignoreAddress = false;
//Decide which WHERE clauses we are going to turn off because of something.
if(something)
ignoreFirstName = true;
//Create the query
var queryCustomers = from c in db.Customers
where (ignoreFirstName || (c.ContactFirstName.Contains("BlackListed")))
where (ignoreLastName || (c.ContactLastName.Contains("BlackListed")))
where (ignoreAddress || (c.Address.Contains("BlackListed"))
select j;
If ignoreFirstName is true in the query then the condition on the other side of the or statement will be ignored.
如果查询中的 ignoreFirstName 为真,则 or 语句另一侧的条件将被忽略。
回答by Omer van Kloeten
Since this is not LINQ to Objects, but rather LINQ to SQL, you have no other alternative beside using either Expressions or a stored procedure.
由于这不是 LINQ to Objects,而是 LINQ to SQL,因此除了使用表达式或存储过程之外,您别无选择。

