Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store Linq where condition in property

I'd like to know the most maintainable way (if exists) to store an entity condition in a parameter so to reuse it in every linq where conditions.

Suppose to have a Product entity:

public class Product
{
    public bool IsDiscontinued { get; set; }

    public int UnitsInStock { get; set; }
}

I'd like to add to the Product class a property IsOnSale that contains the logic to determine whether the product is on sale or not. In this simple example the logic could be:

IsOnSale = IsDiscontinued == false && UnitsInStock > 0

Then I should be able to write a linq query of this type:

from p in context.Products
where p.IsOnSale == true
select p

The purpose of the solution should be that, if in the future the logic to determine whether the product is on sale or not changes (e.g. adding a property IsBackOrderAllowed), I don't have to edit the linq queries everywhere but simply have to change the IsOnSale property.

A similar question has been posted here but seems to address a more specific problem.

like image 391
EdoT Avatar asked Feb 25 '23 19:02

EdoT


2 Answers

You could make a method that returns an IQueryable filtered by your conditions:

public IQueryable<Product> WhereOnSale(this IQueryable<Product> source)
{
    return source.Where(p => p.IsDiscontinued == false && p.UnitsInStock > 0);
}

and you would use it like this:

from p in context.Products.WhereOnSale()
select p

If you want to do it with an expression like in Yakimych's answer then this would work:

Expression<Func<Product, bool>> isOnSale = 
(p => p.IsDiscontinued == false && p.UnitsInStock > 0);

and you could use it like so:

context.Products.Where(isOnSale)

It is important that it is declared as an expression, otherwise Entity Framework won't be able to translate it into SQL because the lambda will be compiled into IL instead of an Expression Tree.

like image 126
Doctor Jones Avatar answered Mar 06 '23 22:03

Doctor Jones


You can do something like this:

Func<Product, bool> isOnSaleFunc = 
                          (p => p.IsDiscontinued == false && p.UnitsInStock > 0);

Then in your query you do:

context.Products.Where(isOnSaleFunc)

Update

As a result of the comment-discussion with @DoctaJonez - the filtering with such an approach will be performed on the client-side (which is or course inefficient), thus Expression<Func<Product, bool>> should be used instead of Func<Product,bool>.

like image 25
Yakimych Avatar answered Mar 06 '23 22:03

Yakimych