0

Using EF6 + SQL Server 2008 R2 + .NET Fx 4.5.

I need to search a particular string in multiple fields of my entity and its related entities and return the records where the search string is found in ANY of the fields. Here's the relevant code:

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

The problem is that there is no OR_FUNCTION in LINQ. You can simulate an optional AND_FUNCTION by calling another Where on the Query object, but I need to do OR here.

I have tried to use If and IIf inside the predicate too, but seemingly can't do that without introducing a compile- or run-time error. What's the correct way of doing this?

2 Answers 2

2

First Way

The tricky way would be to use the logic rule of A OR B equals 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.

Second Way

What about building a predicate using PredicateBuilder and than use it in your Where clause?

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)

Code taken from here.

Third Way

Another possible way is by using Expression Trees to Build Dynamic Queries

Sign up to request clarification or add additional context in comments.

7 Comments

I'm trying to avoid any 3rd-party libraries. This is pretty basic problem and should be solvable within the bounds of framework. Thanks for the tip anyway.
I think this might be what you are looking for (Use Expression Trees to Build Dynamic Queries): msdn.microsoft.com/en-us/library/vstudio/bb882637.aspx
Another way is to make some logical tricks. Like: NOT(NOT(A) AND NOT(B)) equals (A OR B). So just make your first statement with Not() and in the () put all elements with Not x.Contains("some string"). See the edited answer.
These are really good suggestions. I figured out another, somewhat simpler way of doing this. See my answer below. +1 for the great tricks.
@dotNet, about your answer: I think the True in the IF statement should be False, shouldn't it? And another thing: If your goal is to make extra different calls to Query.Where - can it be done your way?
|
1

Found it. You can actually use the new inline If syntax to include optional Or into the above query. Just like this:

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

Note that this works with Option Strict on, i.e. If can infer the type of return value as boolean. @ilanS's answers are good too, but this one seems simpler and more natural.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.