[英]How can I conditionally apply a Linq operator?
我们正在开发日志查看器。 使用将可以选择按用户、严重性等进行过滤。在 SQL 时代,我会添加到查询字符串中,但我想使用 Linq 来完成。 如何有条件地添加 where-clauses?
如果您只想在通过某些条件时进行过滤,请执行以下操作
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 将正是您所需要的。
如果您需要基于列表/数组进行过滤,请使用以下命令:
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();
}
我结束时使用了类似于 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();
这会在访问数据库之前构建查询。 该命令将在最后运行 until.ToList() 。
我使用扩展方法解决了这个问题,允许在流畅的表达式中间有条件地启用 LINQ。 这消除了使用if
语句分解表达式的需要。
.If()
扩展方法:
public static IQueryable<TSource> If<TSource>(
this IQueryable<TSource> source,
bool condition,
Func<IQueryable<TSource>, IQueryable<TSource>> branch)
{
return condition ? branch(source) : source;
}
这允许您这样做:
return context.Logs
.If(filterBySeverity, q => q.Where(p => p.Severity == severity))
.If(filterByUser, q => q.Where(p => p.User == user))
.ToList();
这里还有一个IEnumerable<T>
版本,它将处理大多数其他 LINQ 表达式:
public static IEnumerable<TSource> If<TSource>(
this IEnumerable<TSource> source,
bool condition,
Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
{
return condition ? branch(source) : source;
}
谈到条件 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;
}
这样做:
bool lastNameSearch = true/false; // depending if they want to search by last name,
在where
语句中有这个:
where (lastNameSearch && name.LastNameSearch == "smith")
意味着在创建最终查询时,如果lastNameSearch
为false
,则查询将完全忽略任何用于姓氏搜索的 SQL。
另一种选择是使用类似于此处讨论的 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,这是此方法工作所必需的。 我在这里有一个关于这个问题的问题。
这不是最漂亮的东西,但您可以使用 lambda 表达式并选择性地传递您的条件。 在 TSQL 中,我做了很多以下操作来使参数可选:
WHERE Field = @FieldVar 或 @FieldVar 为 NULL
您可以使用以下 lambda 复制相同的样式(检查身份验证的示例):
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);
用户 foundUser = db.Users.SingleOrDefault(checkUser);
}
我最近有类似的要求,最终在他的 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;
您可以创建和使用此扩展方法
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
return isToExecute ? source.Where(predicate) : source;
}
只需使用 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 ) {
...
}
这可行,但不能分解为表达式树,这意味着 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”的列表。
您可以通过在对所有谓词进行 OR 运算的完全不同的函数中对谓词执行 foreach 来优化它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.