有条件的Linq查询
我们正在使用日志查看器。 使用将有select按用户,严重程度等进行过滤。在Sql的日子里,我会添加到查询string,但我想用Linq做到这一点。 我怎样才能有条件地添加where子句?
如果只想通过某些标准进行过滤,请执行此类操作
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);
这样做将使您的expression式树正是你想要的。 这样,所创build的SQL将正是你所需要的,而不是什么。
如果您需要过滤基于列表/数组,请使用以下命令:
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(); }
我结束了使用类似达人的答案,但与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();
在创build数据库之前build立查询。 直到.ToList()结束后,该命令才会运行。
当谈到有条件的LINQ,我非常喜欢filter和pipe道模式。
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
基本上你为每个filter案例创build一个扩展方法,接受IQueryable和一个参数。
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; }
另一个select是使用像这里讨论的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;
请注意,我只有这样才能使用Linq 2 SQL。 EntityFramework不实现此方法的工作所需的Expression.Invoke。 我在这里有一个关于这个问题的问题。
这样做:
bool lastNameSearch = true/false; // depending if they want to search by last name,
在where
语句中有这个:
where (lastNameSearch && name.LastNameSearch == "smith")
意味着在创build最终查询时,如果lastNameSearch
为false
,查询将完全忽略用于姓氏search的任何SQL。
这不是最漂亮的事情,但你可以使用lambdaexpression式,并可选地传递你的条件。 在TSQL中我做了很多以下的参数可选:
WHERE Field = @FieldVar OR @FieldVar IS NULL
您可以使用下面的lambda(检查身份validation的示例)复制相同的样式:
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);
用户foundUser = db.Users.SingleOrDefault(checkUser);
}
我最近有一个类似的要求,最终在他MSDN中find了这个。 Visual Studio 2008的CSharp示例
下载的DynamicQuery示例中包含的类允许您在运行时按以下格式创builddynamic查询:
var query = db.Customers. Where("City = @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("new(CompanyName as Name, Phone)");
使用这个,你可以在运行时dynamic地创build一个查询string,并将它传递给Where()方法:
string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; var q = from c in db.Customers.Where(queryString, null) orderby c.CompanyName select c;
只要使用C#的&&运算符:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
编辑:啊,需要仔细阅读。 你想知道如何有条件地添加额外的子句。 在这种情况下,我不知道。 :)我可能会做的只是准备几个查询,并执行正确的,这取决于我最终需要什么。
您可以使用外部方法:
var results = from rec in GetSomeRecs() where ConditionalCheck(rec) select rec; ... bool ConditionalCheck( typeofRec input ) { ... }
这将工作,但不能被分解成expression式树,这意味着Linq到SQL将运行检查代码对每个logging。
或者:
var results = from rec in GetSomeRecs() where (!filterBySeverity || rec.Severity == severity) && (!filterByUser|| rec.User == user) select rec;
这可能在expression式树中工作,这意味着Linq to SQL将被优化。
那么,我认为你可以把过滤条件放入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);
这导致包含“我”,“meyou”和“mow”的列表。
你可以通过使用谓词来完成foreach的优化,而这个谓词是一个完全不同的函数,或者是所有的谓词。