动态构建查询
嗨,感谢您花时间回答我的问题。动态构建查询
在与Java合作一年半后,我决定切换回.NET。我必须说,我在VS2012中感到宾至如归。
在使用Java时,我遇到了一个hibernate的实现,可以轻松创建动态查询。
想象一下,我有一个带有5个字段的表单,其中只有一个,任何一个必须填充以便我过滤结果。
是有办法,我可以做在C#中的以下内容:
if(txtMunicipality.text.length > 0){
(x => x.municipality == txtMunicipality.text)
}
if(chkboxIsFinished){
(x => x.isfinished == true)
}
等。
所以我C检查每个字段,如果已被填充,则该值添加标准查询..和我完成后,我执行查询检查。有没有办法在C#中做到这一点?
是的,这是可能的。最简单的方法是用delegates,尤其是匿名的。
例如:
Func<YourEntity, bool> filter = (_ => true); // Default value.
if (txtMunicipality.text.length > 0)
{
filter = (x => x.municipality == txtMunicipality.text);
}
else if (chkboxIsFinished)
{
filter = (x => x.isfinished == true);
}
然后你就可以在Where
语句中使用filter
代表在查询中,例如(我想是你的意图 - 如果没有,例如仍然适用,只是不直接适用)
/ LINQ syntax.
var entities = from e in context
where filter(e)
select e;
// Method syntax.
var entities = context.Where(x => filter(x));
// Or simply:
var entities = context.Where(filter);
'context.Where'版本使用委托会真的***坏,如果这个'context'实际上是EF/L2S/NH等;它会在.NET端而不是在原点进行过滤。 –
嗯,你是对的,我有时会忘记IQueryable属性... –
要做到这一点最简单的方法是编写两个查询,即
IQueryable<Foo> query = ... // or possibly IEnumerable<Foo>
if(!string.IsNullOrEmpty(txtMunicipality.text)) {
query = query.Where(x => x.municipality == txtMunicipality.text);
}
if(chkboxIsFinished) {
query = query.Where(x.isfinished);
}
你可以也直接组成表达式树和委托;如果您需要,请指出您拥有的:表达式树与委托。
编辑:这里是你会怎么做,构成表达而不是查询:
static class Program
{
static void Main()
{
Expression<Func<int, bool>> exp1 = x => x > 4;
Expression<Func<int, bool>> exp2 = x => x < 10;
Expression<Func<int, bool>> exp3 = x => x == 36;
var combined = (exp1.AndAlso(exp2)).OrElse(exp3);
// ^^^ equiv to x => (x > 4 && x < 10) || x == 36
}
static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{ // trivial cases
if (x == null) return y;
if (y == null) return x;
// rewrite using the parameter from x throughout
return Expression.Lambda<Func<T, bool>>(
Expression.OrElse(
x.Body,
SwapVisitor.Replace(y.Body, y.Parameters[0], x.Parameters[0])
), x.Parameters);
}
static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> x, Expression<Func<T, bool>> y)
{ // trivial cases
if (x == null) return y;
if (y == null) return x;
// rewrite using the parameter from x throughout
return Expression.Lambda<Func<T, bool>>(
Expression.AndAlso(
x.Body,
SwapVisitor.Replace(y.Body, y.Parameters[0], x.Parameters[0])
), x.Parameters);
}
class SwapVisitor : ExpressionVisitor
{
public static Expression Replace(Expression body, Expression from, Expression to)
{
return new SwapVisitor(from, to).Visit(body);
}
private readonly Expression from, to;
private SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
}
在这篇文章中,你可以找到一些有用的扩展方法,可以让你谓词结合(它应该工作NHibernate的为好):
LINQ to Entities: Combining Predicates
你可以再建一个拉姆达表达这样的:
Expression<Func<MyObject, bool>> predicate = x => true;
if(txtMunicipality.text.length > 0){
predicate = predicate.And(x => x.municipality == txtMunicipality.text);
}
if(chkboxIsFinished){
predicate = predicate.And(x => x.isfinished == true);
}
可能是:http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query -library.aspx – Habib
我认为这个问题不是关于动态LINQ,而是动态构建查询。 –
是的,你是对的..我会编辑我的文章 – Dragan