Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ multiple where clause

I have a course table which I need to search based on keywords typed in the search box. Here is a sample query:

SELECT * FROM Courses WHERE 
Title LIKE '%word%' OR Title LIKE '%excel%' OR 
Contents LIKE '%word%' OR Contents LIKE '%excel%'

How can I convert this in LINQ where LINQ would dynamically generate WHERE statements based on each keywords.

I tried to user PredicateBuilder it works fine as long as the field is VARCHAR. For the "TEXT" fields the quotes are not generated thus causing compiler to give an error message. Here is the SQL generated by PredicateBuilder

SELECT [t0].[CoursesID], [t0].[Title], [t0].[Contents], [t0].[Active], 
FROM [dbo].[Courses] AS [t0]
WHERE ([t0].[Title] LIKE '%word%') OR ([t0].[Contents] LIKE %word%) OR 
([t0].Title] LIKE '%excel%') OR ([t0].[Contents] LIKE %excel%)

Notice there is no single Quote for the "Contents" field which is a Text field in the database.

Is there any easy way to build WHERE statement and attach it with query? Does anyone know how I can do this without PredicateBuilder?

Thanks in advance.

like image 540
Amir Avatar asked Feb 28 '09 11:02

Amir


People also ask

Can we use multiple where clause in LINQ?

Well, you can just put multiple "where" clauses in directly, but I don't think you want to. Multiple "where" clauses ends up with a more restrictive filter - I think you want a less restrictive one.

How to write select LINQ query in c#?

In a LINQ query, the first step is to specify the data source. In C# as in most programming languages a variable must be declared before it can be used. In a LINQ query, the from clause comes first in order to introduce the data source ( customers ) and the range variable ( cust ).

How does LINQ select work?

Select is used to project individual element from List, in your case each customer from customerList . As Customer class contains property called Salary of type long, Select predicate will create new form of object which will contain only value of Salary property from Customer class.


1 Answers

Since you are working w/ LINQ I suppose you are working against a LINQ-to-SQL data context right? I don't have a spare DataContext lying around to test this, but this should give you some ideas.

I don't know if it will work against data context though, but most of these are pretty basic stuff (chaining OR operator and Contains method call) so it shouldn't cause problem when the query translates to SQL.

First I create a custom function that would build my predicate:

Func<string, Func<DataItem, bool>> buildKeywordPredicate =
    keyword =>
        x => x.Title.Contains(keyword)
            || x.Contents.Contains(keyword);

This is a function which takes a single string keyword and then return another function which takes a DataItem and checks it against the keyword.

Basically, if you pass in "Stack", you'll get a predicate: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack").

Next, since there are many possible keywords and you need to chain it with an OR operation, I create another helper function to chain 2 predicates together with an OR

Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate =
    (pred1, pred2) =>
        x => pred1(x) || pred2(x);

This function takes 2 predicates and then join them up with an OR operation.

Having those 2 functions, I can then build my where predicate like this:

foreach (var word in keywords) {            
    filter = filter == null
        ? buildKeywordPredicate(word)
        : buildOrPredicate(filter, buildKeywordPredicate(word));
}

The first line inside the loop basically checks if the filter is null. If it is, then we want a simple keyword filter built for us.

Else if the filter is not null, we need to chain existing filters with an OR operation, so we pass the existing filter and a new keyword filter to buildOrPredicate to do just that.

And then we can now create the WHERE part of the query:

var result = data.Where(filter);

Passing in the complicated predicate we've just built.

I don't know if this will different from using PredicateBuilder but since we are deferring query translation to the LINQ-to-SQL engine, there should not be any problems.

But as I said, I havn't tested it against a real data context, so if there's any problems you can write in the comments.

Here's the console app that I built to test: http://pastebin.com/feb8cc1e

Hope this helps!


EDIT: For a more generic and reusable version which involves properly utilizing the Expression Trees in LINQ, check out Thomas Petricek's blog post: http://tomasp.net/articles/dynamic-linq-queries.aspx

like image 130
chakrit Avatar answered Oct 24 '22 16:10

chakrit