构造动态lambda

时间:2014-06-16 11:54:35

标签: vb.net linq entity-framework lambda

使用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 。您可以通过调用Where对象上的另一个Query来模拟可选的 AND_FUNCTION ,但我需要在此处执行OR。

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

2 个答案:

答案 0 :(得分:2)

第一种方式

棘手的方法是使用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.

第二种方式

如何使用predicate构建PredicateBuilder而不是在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

答案 1 :(得分:1)

找到它。您实际上可以使用新的内联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 on,即If可以将返回值的类型推断为boolean。 @ ilanS的答案也很好,但这个答案看起来更简单,更自然。