【问题标题】:Dynamically building queries动态构建查询
【发布时间】:2012-11-23 03:31:58
【问题描述】:

您好,感谢您抽出宝贵时间回答我的问题。

在使用 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# .net linq dynamic


【解决方案1】:

最简单的方法是组合两个查询,即

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);
        }
    }
}

【讨论】:

    【解决方案2】:

    是的,这是可能的。最简单的方法是使用 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);
    }
    

    然后您可以在查询中使用 filter 委托,例如在 Where 语句中(我想这是您的意图 - 如果不是,该示例仍然相关,只是不直接适用)

    / 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 实际上是 EF / L2S / NH 等,则使用委托的 context.Where 版本会真的很糟糕;它将在 .NET 端而不是在源端进行过滤。
    【解决方案3】:

    在本文中,您可以找到一些有用的扩展方法,这些方法允许您组合谓词(它也应该适用于 NHibernate):

    LINQ to Entities: Combining Predicates

    然后你可以像这样构建一个 lambda 表达式:

    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);
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-08
      • 2012-12-21
      • 2018-12-21
      • 1970-01-01
      • 1970-01-01
      • 2013-08-12
      • 2019-06-24
      • 2020-12-03
      • 1970-01-01
      相关资源
      最近更新 更多