Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ and optional parameters

I'm designing a web service to be consumed by an MVC app (pretty simple stuff), but I need a single method in the web service that takes up to four optional parameters (i.e. catId, brandId, lowestPrice and highestPrice).

How do I write the Linq query so that it essentially executes

databaseObject.Products.Where(p=> (p.Category == ANY if catId==null, else catId))

I hope that makes sense.

like image 377
Will Whitehead Avatar asked Oct 23 '15 14:10

Will Whitehead


4 Answers

The parameters of the method could accept null values and the Where restriction could be evaluated for each not null parameter:

IQueryable<Product> q = databaseObject.Products;

if (catId != null)
{
    q = q.Where(p => p.Category == catId);
}
if (brandId != null)
{
    q = q.Where(p => p.Brand == brandId);
}
// etc. the other parameters

var result = q.ToList();
like image 83
Martin Staufcik Avatar answered Jan 08 '23 11:01

Martin Staufcik


If this is Linq To SQL:

databaseObject.Products.Where(p=> (catId == null || p.Category == catId) );

Linq To SQL, efficiently writes the SQL sent to backend without a where clause if CatId is null. You can have multiple of these constructs, and only those with a nonNull value is included in the where construct.

like image 37
Cetin Basoz Avatar answered Jan 08 '23 10:01

Cetin Basoz


databaseObject.Products.Where(p=> ((catId==null) ||  (p.Category == catId)))

For your other 3 optional parameters, you can AND them in, doing your entire search in one linq statement.

like image 33
Joe Avatar answered Jan 08 '23 10:01

Joe


Something along the lines of the following should do the trick:

IEnumerable<Product> GetProducts(int? categoryId)
{
    var result = databaseObject.Products.Where(product => ProductCategoryPredicate(product, categoryId)
}

/// <summary>
/// Returns true if the passed in categoryId is NULL
/// OR if it's not null, if the passed in categoryId matches that
/// of the passed in product
///
/// This method will get called once for each product returned from 
/// databaseObject.Products</summary>
bool ProductCategoryPredicate(Product product, int? categoryId)
{
    if (categoryId.HasValue)
    {
        return product.Category == categoryId.Value;
    }
    else
    {
        return true;
    }
}

This could/can be simplified into a single line LINQ statement (see below) but I've written it long-hand above for clarity:

IEnumerable<Product> GetProducts(int? categoryId)
{
    var result = databaseObject.Products.Where(product => !categoryId.HasValue || product.Category == categoryId.Value);
}
like image 37
Rob Avatar answered Jan 08 '23 11:01

Rob