C# 条件 Linq 查询
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11194/
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
Conditional Linq Queries
提问by sgwill
We're working on a Log Viewer. The use will have the option to filter by user, severity, etc. In the Sql days I'd add to the query string, but I want to do it with Linq. How can I conditionally add where-clauses?
我们正在开发日志查看器。用户可以选择按用户、严重性等进行过滤。在 Sql 时代,我会添加到查询字符串中,但我想用 Linq 来做。如何有条件地添加 where 子句?
采纳答案by Darren Kopp
if you want to only filter if certain criteria is passed, do something like this
如果您只想过滤某些条件是否通过,请执行以下操作
var logs = from log in context.Logs
select log;
if (filterBySeverity)
logs = logs.Where(p => p.Severity == severity);
if (filterByUser)
logs = logs.Where(p => p.User == user);
Doing so this way will allow your Expression tree to be exactly what you want. That way the SQL created will be exactly what you need and nothing less.
这样做将使您的表达式树完全符合您的要求。这样创建的 SQL 将正是您所需要的。
回答by TheSmurf
Just use C#'s && operator:
只需使用 C# 的 && 运算符:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Edit: Ah, need to read more carefully. You wanted to know how to conditionallyadd additional clauses. In that case, I have no idea. :) What I'd probably do is just prepare several queries, and execute the right one, depending on what I ended up needing.
编辑:啊,需要更仔细地阅读。您想知道如何有条件地添加附加子句。在那种情况下,我不知道。:) 我可能要做的只是准备几个查询,然后根据我最终需要的内容执行正确的查询。
回答by Keith
You could use an external method:
您可以使用外部方法:
var results =
from rec in GetSomeRecs()
where ConditionalCheck(rec)
select rec;
...
bool ConditionalCheck( typeofRec input ) {
...
}
This would work, but can't be broken down into expression trees, which means Linq to SQL would run the check code against every record.
这会起作用,但不能分解为表达式树,这意味着 Linq to SQL 将对每条记录运行检查代码。
Alternatively:
或者:
var results =
from rec in GetSomeRecs()
where
(!filterBySeverity || rec.Severity == severity) &&
(!filterByUser|| rec.User == user)
select rec;
That might work in expression trees, meaning Linq to SQL would be optimised.
这可能适用于表达式树,这意味着将优化 Linq to SQL。
回答by Jon Limjap
Well, what I thought was you could put the filter conditions into a generic list of Predicates:
好吧,我认为您可以将过滤条件放入谓词的通用列表中:
var list = new List<string> { "me", "you", "meyou", "mow" };
var predicates = new List<Predicate<string>>();
predicates.Add(i => i.Contains("me"));
predicates.Add(i => i.EndsWith("w"));
var results = new List<string>();
foreach (var p in predicates)
results.AddRange(from i in list where p.Invoke(i) select i);
That results in a list containing "me", "meyou", and "mow".
这会生成一个包含“me”、“meyou”和“mow”的列表。
You could optimize that by doing the foreach with the predicates in a totally different function that ORs all the predicates.
您可以通过在一个完全不同的函数中对谓词执行 foreach 来优化它,该函数对所有谓词进行 OR 运算。
回答by t3rse
It isn't the prettiest thing but you can use a lambda expression and pass your conditions optionally. In TSQL I do a lot of the following to make parameters optional:
这不是最漂亮的事情,但您可以使用 lambda 表达式并选择性地传递您的条件。在 TSQL 中,我做了很多以下工作来使参数可选:
WHERE Field = @FieldVar OR @FieldVar IS NULL
WHERE 字段 = @FieldVar 或 @FieldVar 为 NULL
You could duplicate the same style with a the following lambda (an example of checking authentication):
您可以使用以下 lambda 复制相同的样式(检查身份验证的示例):
MyDataContext db = new MyDataContext();
void RunQuery(string param1, string param2, int? param3){
Func checkUser = user =>
((param1.Length > 0)? user.Param1 == param1 : 1 == 1) &&
((param2.Length > 0)? user.Param2 == param2 : 1 == 1) &&
((param3 != null)? user.Param3 == param3 : 1 == 1);
User foundUser = db.Users.SingleOrDefault(checkUser);
}
MyDataContext db = new MyDataContext();
void RunQuery(string param1, string param2, int? param3){
Func checkUser = 用户 =>
((param1.Length > 0)? user.Param1 == param1 : 1 == 1) &&
((param2.Length > 0)? user.Param2 == param2 : 1 == 1) &&
((param3 != null)? user.Param3 == param3 : 1 == 1);
用户找到用户 = db.Users.SingleOrDefault(checkUser);
}
回答by Lars M?hlum
When it comes to conditional linq, I am very fond of the filters and pipes pattern.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
说到条件 linq,我非常喜欢过滤器和管道模式。
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
Basically you create an extension method for each filter case that takes in the IQueryable and a parameter.
基本上,您为每个接受 IQueryable 和参数的过滤器案例创建一个扩展方法。
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
回答by Brad Leach
Another option would be to use something like the PredicateBuilder discussed here. It allows you to write code like the following:
另一种选择是使用类似于此处讨论的 PredicateBuilder 的东西。它允许您编写如下代码:
var newKids = Product.ContainsInDescription ("BlackBerry", "iPhone");
var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
.And (Product.IsSelling());
var query = from p in Data.Products.Where (newKids.Or (classics))
select p;
Note that I've only got this to work with Linq 2 SQL. EntityFramework does not implement Expression.Invoke, which is required for this method to work. I have a question regarding this issue here.
请注意,我只将它用于 Linq 2 SQL。EntityFramework 不实现 Expression.Invoke,这是此方法工作所必需的。我在这里有一个关于这个问题的问题。
回答by Andy Rose
I had a similar requirement recently and eventually found this in he MSDN. CSharp Samples for Visual Studio 2008
我最近有一个类似的要求,最终在他的 MSDN 中找到了这个。 Visual Studio 2008 的 CSharp 示例
The classes included in the DynamicQuery sample of the download allow you to create dynamic queries at runtime in the following format:
下载的 DynamicQuery 示例中包含的类允许您在运行时按以下格式创建动态查询:
var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
Using this you can build a query string dynamically at runtime and pass it into the Where() method:
使用它,您可以在运行时动态构建查询字符串并将其传递给 Where() 方法:
string dynamicQueryString = "City = \"London\" and Order.Count >= 10";
var q = from c in db.Customers.Where(queryString, null)
orderby c.CompanyName
select c;
回答by sgwill
I ended using an answer similar to Daren's, but with an IQueryable interface:
我最终使用了类似于 Daren 的答案,但使用了 IQueryable 接口:
IQueryable<Log> matches = m_Locator.Logs;
// Users filter
if (usersFilter)
matches = matches.Where(l => l.UserName == comboBoxUsers.Text);
// Severity filter
if (severityFilter)
matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);
Logs = (from log in matches
orderby log.EventTime descending
select log).ToList();
That builds up the query before hitting the database. The command won't run until .ToList() at the end.
这会在访问数据库之前建立查询。该命令直到 .ToList() 最后才会运行。
回答by Carlos
If you need to filter base on a List / Array use the following:
如果您需要根据列表/数组进行过滤,请使用以下内容:
public List<Data> GetData(List<string> Numbers, List<string> Letters)
{
if (Numbers == null)
Numbers = new List<string>();
if (Letters == null)
Letters = new List<string>();
var q = from d in database.table
where (Numbers.Count == 0 || Numbers.Contains(d.Number))
where (Letters.Count == 0 || Letters.Contains(d.Letter))
select new Data
{
Number = d.Number,
Letter = d.Letter,
};
return q.ToList();
}