【问题标题】:Constructing dynamic lambda构造动态 lambda
【发布时间】:2014-06-16 11:54:35
【问题描述】:

使用 EF6 + SQL Server 2008 R2 + .NET Fx 4.5。

我需要在我的实体及其相关实体的多个字段中搜索特定字符串,并返回在任何字段中找到搜索字符串的记录。以下是相关代码:

Dim Query = MyDB.items.AsQueryable()

Query = Query.Where(Function(r) _
                              r.stock_no.Contains(searchString) OrElse _
                              r.serial_number.Contains(searchString) OrElse _
                              r.catalog_item.description.Contains(searchString) OrElse _                                 r.catalog_item.category.Contains(searchString) OrElse _
                              r.item_status.name.Contains(searchString) OrElse _
                              r.notes.Contains(searchString))

If r.issued_to_company_id.HasValue Then 'This is a nullable field (0-1 relation)
    Query = Query.OR_FUNCTION(Function(r) r.issued_to_company.name.Contains(searchString))
End If

问题是LINQ中没有OR_FUNCTION。您可以通过在 Query 对象上调用另一个 Where 来模拟可选的 AND_FUNCTION,但我需要在此处执行 OR。

我也尝试在谓词中使用IfIIf,但如果不引入编译或运行时错误,似乎无法做到这一点。这样做的正确方法是什么?

【问题讨论】:

    标签: vb.net linq entity-framework lambda


    【解决方案1】:

    第一道

    棘手的方法是使用A OR B等于NOT(NOT A AND NOT B)的逻辑规则:

    ' Assuming QueryAll holds all values
    Query = QueryAll.Where(Function(r) _ 
                                  Not r.stock_no.Contains(searchString) Andalso _
                                  Not r.serial_number.Contains(searchString) Andalso _
                                  Not r.catalog_item.description.Contains(searchString) Andalso _                                  Not r.catalog_item.category.Contains(searchString) Andalso _
                                  Not r.item_status.name.Contains(searchString) Andalso _
                                  Not r.notes.Contains(searchString))
    
    ' Query will hold all rows which DO NOT contain searchString.
    Query = Query.Where(Function(r) Not r.issued_to_company.name.Contains(searchString))
    ' Here you should choose all elements in QueryAll which are not in Query. 
    ' The result would be all rows containing searchString.
    

    第二种方式

    使用PredicateBuilder 构建一个predicate 然后在你的Where 子句中使用它怎么样?

    Dim pred = PredicateBuilder.True(Of MyClass)()    
    pred = pred.And(Function(m As MyClass) m.SomeProperty = someValue)
    pred = pred.Or(Function(m As MyClass) m.SomeProperty = someValue)
    

    代码取自here

    第三条路

    另一种可能的方法是使用Expression Trees to Build Dynamic Queries

    【讨论】:

    • 我试图避免使用任何第三方库。这是一个非常基本的问题,应该可以在框架范围内解决。无论如何感谢您的提示。
    • 我认为这可能是您正在寻找的(使用表达式树构建动态查询):msdn.microsoft.com/en-us/library/vstudio/bb882637.aspx
    • 另一种方法是做一些合乎逻辑的技巧。比如:NOT(NOT(A) AND NOT(B)) 等于 (A OR B)。因此,只需使用 Not() 进行您的第一个语句,并在 () 中使用 Not x.Contains("some string") 放置所有元素。请参阅编辑后的答案。
    • 这些都是非常好的建议。我想出了另一种更简单的方法。请看下面我的回答。为伟大的技巧 +1。
    • @dotNet,关于您的回答:我认为IF 语句中的True 应该是False,不是吗?还有一件事:如果您的目标是对Query.Where 进行更多不同的调用 - 可以按照您的方式完成吗?
    【解决方案2】:

    找到了。您实际上可以使用新的内联 If 语法将可选的 Or 包含到上述查询中。就像这样:

    Query = Query.Where(Function(r) _
               r.stock_no.Contains(searchString) OrElse _
               r.serial_number.Contains(searchString) OrElse _
               r.catalog_item.description.Contains(searchString) OrElse _
               r.catalog_item.category.Contains(searchString) OrElse _
               r.item_status.name.Contains(searchString) OrElse _
               r.notes.Contains(searchString) OrElse _
               If(r.catalog_item.manufacturer_id.HasValue, r.catalog_item.manufacturer_company.name.Contains(searchString), True))
    

    请注意,这适用于Option Strict,即If 可以将返回值的类型推断为布尔值。 @ilanS 的回答也不错,不过这个看起来更简单自然。

    【讨论】:

      猜你喜欢
      • 2014-11-14
      • 1970-01-01
      • 2021-06-19
      • 1970-01-01
      • 2021-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-06
      相关资源
      最近更新 更多