views:

105

answers:

3

Howdy,

I've figured out how to do conditional queries with linq to sql and I've also figured out how to OR where clauses. Unfortunately I can't figure out how to do both at once. I can do a conditional where clause something like:

var ResultsFromProfiles = from AllPeeps in SearchDC.aspnet_Users
                          select AllPeeps;


if (SearchFirstNameBox.Checked)
{
    ResultsFromProfiles = ResultsFromProfiles.Where(p => p.tblUserProfile.FirstName.Contains(SearchTerm));
}

if (SearchLastNameBox.Checked)
{
    ResultsFromProfiles = ResultsFromProfiles.Where(p => p.tblUserProfile.LastName.Contains(SearchTerm));
}

This will get me any profiles where the first name AND the last name contain the search term.

Or I could do:

var ResultsFromProfiles = from p in SearchDC.aspnet_Users
                          where p.tblUserProfile.LastName.Contains(SearchTerm) ||
                                p.tblUserProfile.FirstName.Contains(SearchTerm)
                          select p;

This would get me any profiles where the first name OR the last name contains the search term.

I have a bunch of checkboxes where the user can specify which fields they want to search for teh search term, so I want to be able to build a query that will conditionally add them as in the first code snippet above, but add them as an OR so they work like the second snippet. That way it will search for any matches anywhere in the specified fields.

Any tips?

+4  A: 

Yeah, use PredicateBuilder. It lets you build up dynamic queries with And or Or semantics. It's free and stable- I use it all over the place.

nitzmahone
OMG I did not know about that predicateBuilder
Matias
Ooh, that looks nice. Especially compared with the alternative suggestion (see my entry below)
Andrew Shepherd
Brilliant, this is exactly what I needed and very simple/elegant.Thanks
Adam
A: 

Here's a suggestion.

I haven't tried compiling and running it, and LinqToSQL is full of surprises, so no guarantees :-)

var ResultsFromProfiles = from AllPeeps in SearchDC.aspnet_Users select AllPeeps;

IEnumerable<AspNet_User> total = new AspNew_User[0];

if (SearchFirstNameBox.Checked)
{    
    total = total.Concat(ResultsFromProfiles.Where(p => p.tblUserProfile.FirstName.Contains(SearchTerm));}
}

if (SearchLastNameBox.Checked)
{
   total = total.Concat(ResultsFromProfiles.Where(p => p.tblUserProfile.LastName.Contains(SearchTerm));
}

total = total.Distinct();
Andrew Shepherd
+1  A: 

One way to do this is to manipulate the LINQ expression tree for your query. In your case, you'd need to build a lambda expression and substitute it in for your call to Where. Here is a working example based on a list, but the code to manipulate the expression tree is the same regardless of the query provider.

List<User> Users = new List<User>();
Users.Add(new User() { FirstName = "John", LastName = "Smith" });
Users.Add(new User() { FirstName = "Jane", LastName = "Smith" });


string Query = "John";

var Queryable = Users.AsQueryable();

var Results = (from u in Queryable
         select u);

//initial method call... the lambda u => false is a place-holder that is about to be replaced
MethodCallExpression WhereExpression = (MethodCallExpression)Results.Where(u => false).Expression;

//define search options
Expression<Func<User, string, bool>> FilterLastName = (u, query) => u.LastName.Contains(query);
Expression<Func<User, string, bool>> FilterFirstName = (u, query) => u.FirstName.Contains(query);

//build a lambda based on selected search options... tie the u parameter to UserParameter and the query parameter to our Query constant
ParameterExpression UserParameter = Expression.Parameter(typeof(User), "u");
Expression Predicate = Expression.Constant(false);  //for simplicity, since we're or-ing, we'll start off with false || ...

//if (condition for filtering by last name)
{
    Predicate = Expression.Or(Predicate, Expression.Invoke(FilterLastName, UserParameter, Expression.Constant(Query)));
}

//if (condition for filtering by first name)
{
    Predicate = Expression.Or(Predicate, Expression.Invoke(FilterFirstName, UserParameter, Expression.Constant(Query)));
}

//final method call... lambda u => false is the second parameter, and is replaced with a new lambda based on the predicate we just constructed
WhereExpression = Expression.Call(WhereExpression.Object, WhereExpression.Method, WhereExpression.Arguments[0], Expression.Lambda(Predicate, UserParameter));

//get a new IQueryable for our new expression
Results = Results.Provider.CreateQuery<User>(WhereExpression);

//enumerate results as usual
foreach (User u in Results)
{
    Console.WriteLine("{0} {1}", u.FirstName, u.LastName);
}

Working with expression trees can typically be simplified by using the visitor pattern, but I've omitted that so you could more clearly see the work that has to be done.

Michael Petito