条件Linq查询
我们正在研究日志查看器。使用时可以选择按用户,严重性等进行过滤。在Sql天内,我将添加到查询字符串中,但是我想使用Linq进行过滤。如何有条件地添加子句?
解决方案
回答
只需使用C#的&&运算符即可:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
编辑:嗯,需要仔细阅读。我们想知道如何有条件地添加其他子句。在那种情况下,我不知道。 :)我可能要做的只是准备几个查询,然后根据我最终需要执行的查询来执行正确的查询。
回答
如果仅在通过某些条件时才进行过滤,请执行以下操作
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);
这样,表达式树将完全符合要求。这样,创建的SQL正是我们所需要的,而且仅此而已。
回答
我们可以使用外部方法:
var results = from rec in GetSomeRecs() where ConditionalCheck(rec) select rec; ... bool ConditionalCheck( typeofRec input ) { ... }
这是可行的,但不能分解成表达式树,这意味着Linq to SQL将对每条记录运行检查代码。
或者:
var results = from rec in GetSomeRecs() where (!filterBySeverity || rec.Severity == severity) && (!filterByUser|| rec.User == user) select rec;
这可能在表达式树中起作用,这意味着将优化Linq to SQL。
回答
好吧,我认为我们可以将过滤条件放入通用谓词列表中:
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);
这将导致包含" me"," meyou"和" mow"的列表。
我们可以通过对谓词使用foreach进行完全优化,以对所有谓词进行完全不同的功能。
回答
这不是最漂亮的东西,但是我们可以使用lambda表达式并可选地传递条件。在TSQL中,我做了很多以下操作以使参数成为可选参数:
WHERE Field = @FieldVar OR @FieldVar IS NULL
我们可以使用以下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);
用户foundUser = db.Users.SingleOrDefault(checkUser);
}
回答
对于条件linq,我非常喜欢过滤器和管道模式。
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
基本上,我们为每个接受IQueryable和参数的过滤器案例创建一个扩展方法。
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; }
回答
另一个选择是使用此处讨论的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,此方法必须使用Expression.Invoke。我对此有一个疑问。
回答
最近我有一个类似的要求,最终在MSDN中找到了这个要求。
Visual Studio 2008的CSharp示例
下载的DynamicQuery示例中包含的类使我们可以在运行时以以下格式创建动态查询:
var query = db.Customers. Where("City = @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("new(CompanyName as Name, Phone)");
使用此方法,我们可以在运行时动态构建查询字符串,并将其传递给Where()方法:
string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; var q = from c in db.Customers.Where(queryString, null) orderby c.CompanyName select c;
回答
我使用了类似于达人的答案,但是有了一个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();
这将在命中数据库之前建立查询。该命令直到.ToList()最后才运行。