I am wondering whether I can simplify my code below, especially the following 2 statements:
// Statement A
Expression<Func<Product, bool>>? criteria = p =>
(id == null ? true : p.Id == id) &&
(name == null ? true : p.Name.ToLower().Contains(name.ToLower())) &&
(maxPrice == null ? true : p.Price <= maxPrice);
// Statement B
if (id is null && name is null && maxPrice is null)
criteria = null;
I am not happy with the statement B because of two reasons:
- I have to check again each parameter that has been checked in the statement A.
- It is prone to error (forgetting to check all parameters)
Attempt
The following does not compile because
An expression tree cannot contain an assignment operator.
bool sign = false;
Criteria = p =>
(id == null ? (sign = true) : p.Id == id) &&
(name == null ? (sign = true) : p.Name.ToLower().Contains(name.ToLower()))
;
if (sign == false)
Criteria = null;
Question
Is there any way to make it much simpler and less prone to errors? Any suggestions are always welcome.
static IQueryable<Product> Filter(this IQueryable<Product> products,
int? id = null,
string? name = null,
decimal? maxPrice = null)
{
Expression<Func<Product, bool>>? criteria = p =>
(id == null ? true : p.Id == id) &&
(name == null ? true : p.Name.ToLower().Contains(name.ToLower())) &&
(maxPrice == null ? true : p.Price <= maxPrice);
if (id is null && name is null && maxPrice is null)
criteria = null;
if (criteria is null)
return products;
else
return products.Where(criteria);
}
CodePudding user response:
Just follow the pretty standard pattern of dynamically adding Where
based on presence of filtering conditions:
static IQueryable<Product> Filter(this IQueryable<Product> products,
int? id = null,
string? name = null,
decimal? maxPrice = null)
{
if (id is not null)
{
products = products.Where(p => p.Id == id);
}
if (name is not null)
{
products = products.Where(p => p.Name.ToLower().Contains(name.ToLower()));
}
if (maxPrice is not null)
{
products = products.Where(p => p.Price <= maxPrice);
}
return products;
}
CodePudding user response:
You can check for null on the received parameters, if any are null make that bit of criteria true by checking for null, e.g. (id == null || p.Id== id)
basically says give me all Id's that match the parameter id or if it's null then give me all parameter Ids.
static IQueryable<Product> Filter(this IQueryable<Product> products,
int? id = null,
string? name = null,
decimal? maxPrice = null)
{
Expression<Func<Product, bool>> criteria = p =>
(id == null || p.Id== id) &&
(name == null || p.Name.ToLower().Contains(name.ToLower())) &&
(maxPrice == null || p.Price <= maxPrice);
return products.Where(criteria);
}
This also has the added benefit of making the parameters optional.