Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq with optional WHERE options

Tags:

c#

sql

linq

I have a .Net function that accepts 3 parameters, all optional. Something like this:

public List<MyObject> Search(string colour, string size, string name)
{
     var result = (from c in MyTable where .... select c).ToList();     
}

My question is, what is the best way to do the where part. Would the best be to create dynamic linq? What's the best pattern, within linq, to have optional where parameters?

So, in SQL, something like this:

SELECT *
FROM MyTable
WHERE (@colour <> '' AND colour = @colour)
  AND (@size <> '' AND size = @size)
  AND (@name <> '' AND name = @name)

But I am hoping there a neater, more acceptable pattern for doing this within linq.

like image 821
Craig Avatar asked Oct 04 '15 07:10

Craig


3 Answers

Chain Where clauses with checking for null

var result = context.MyTable
    .Where(t => color == null || color == t.Color)
    .Where(t => size == null || size == t.Size)
    .Where(t => name == null || name == t.Name)
    .ToList();

Alternative approach would be to add conditions only when you need them

var query = context.MyTable;

if (color != null) query = query.Where(t => t.Color == color);
if (size != null) query = query.Where(t => t.Size == size);
if (name != null) query = query.Where(t => t.Name == name);

var result = query.ToList();
like image 185
Fabio Avatar answered Nov 17 '22 21:11

Fabio


In such cases, I would advise you to use the PredicateBuilder to generate your queries. You can copy the code from here or you could install the LinqKit Nuget Package.

Using this code will allow you to generate dynamic queries on the fly and will prevent you from writing tons of if/else statements.

Statements like...

p => p.Price > 100 &&
 p.Price < 1000 &&
 (p.Description.Contains ("foo") || p.Description.Contains ("far"))

will be generated by this kind of code:

var inner = PredicateBuilder.False<Product>();
inner = inner.Or (p => p.Description.Contains ("foo"));
inner = inner.Or (p => p.Description.Contains ("far"));

var outer = PredicateBuilder.True<Product>();
outer = outer.And (p => p.Price > 100);
outer = outer.And (p => p.Price < 1000);
outer = outer.And (inner);

I think this is fairly neat and it will also give you an understanding on how powerful expressions can be.

like image 6
hbulens Avatar answered Nov 17 '22 21:11

hbulens


var results = olstOfObjects.Where(x => 
    (x.size == size || x.size == "") &&
    (x.color == color || x.color == "") &&
    (x.name == name || x.name == "")).ToList();;
like image 2
Sam Jolan Avatar answered Nov 17 '22 23:11

Sam Jolan