【问题标题】:Creating a Linq expression dynamically containing a subquery动态创建包含子查询的 Linq 表达式
【发布时间】:2012-03-04 12:19:48
【问题描述】:

我最近偶然发现了在运行时动态创建 Linq 表达式的问题。我发现的大多数示例都处理相当简单的任务,即仅将给定数据库实体的一个属性与单个参数进行比较。像这样:

 Session.Query.Where(m => m.Name.Contains("test"))

这也可以通过像这样更通用的方法来实现:

var item = Expression.Parameter(typeof (MyClass), "item");
var property = Expression.Property(item, "Name");
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var searchExpression = Expression.Constant(searchString, typeof(string));
var containsMethodExpression = Expression.Call(property, containsMethod, searchExpression);
var lambda = Expression.Lambda<Func<MyClass, bool>>(containsMethodExpression, item);
query = query.Where(lambda);    

但是,有时任务会稍微复杂一些,并且想要达到以下目标:

Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")));

其中“SpecialProperty”属于List类型,而“Name”属于字符串类型。

是否可以动态构建这样的 Linq 表达式,如何实现?这种方法是否存在任何性能问题?

【问题讨论】:

    标签: .net performance linq nhibernate


    【解决方案1】:

    找到了一个适用于我的特定用例的解决方案,并且完全符合我的要求。

    /* 
    building expression tree 
    example: Session.Query.Where(m => m.SpecialProperty.Any(f => f.Name.Contains("test")))
    */ 
    
    var innerItem = Expression.Parameter(typeof(MyInnerClass), "f");
    var innerProperty = Expression.Property(innerItem, "Name");
    var innerMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
    var innerSearchExpression = Expression.Constant(searchString, typeof(string));
    var innerMethodExpression = Expression.Call(innerProperty, innerMethod, new[] { innerSearchExpression });
    var innerLambda = Expression.Lambda<Func<MyInnerClass, bool>>(innerMethodExpression, innerItem);
    
    var outerItem = Expression.Parameter(typeof(MyOuterClass), "m");
    var outerProperty = Expression.Property(outerItem, info.Name);
    /* calling a method extension defined in Enumerable */
    var outerMethodExpression = Expression.Call(typeof(Enumerable), "Any", new[] { typeof(MyInnerClass) }, outerProperty, innerLambda);
    var outerLambda = Expression.Lambda<Func<MyOuterClass, bool>>(outerMethodExpression, outerItem);
    query = query.Where(outerLambda);
    

    需要这种相当过时的方法,而不是更优雅的单行 LINQ-Expression 来允许类型和方法名称的参数化。 但是,我当然不介意关于可能的性能损失的其他建议和想法。

    这段代码很可能sn-p也可以帮助解决How to produce a Subquery using non-generic Lambda

    【讨论】:

      【解决方案2】:

      我建议您查看以下链接:

      约瑟夫和本阿尔巴哈里的PredicateBuilder

      LINQ dynamic query library

      我已经有一段时间没有使用过,但是其中一个应该会有所帮助。

      【讨论】:

        猜你喜欢
        • 2014-05-19
        • 1970-01-01
        • 2014-06-16
        • 1970-01-01
        • 1970-01-01
        • 2019-11-15
        • 2019-03-31
        • 2014-01-31
        • 2015-10-01
        相关资源
        最近更新 更多