Andreea Elena
Andreea Elena

Reputation: 37

c# linq combine Expression<Func<T, bool>> predicate in where clause with another condition

Is it possible to construct a where clause like this, where predicate is of type Expression<Func<T, bool>> predicate:

 var resultQuery = query.Where(q => !q.IsDeleted && predicate).ToList();

I would like to avoid double where clauses like this:

 var resultQuery = query.Where(q => !q.IsDeleted).Where(predicate).ToList();

Upvotes: 1

Views: 6607

Answers (2)

Anton Kovachev
Anton Kovachev

Reputation: 337

IT is impossible. You need to provide a lambda expression as a parameter to the Where clause which would be compiled to an expression tree and after that translated into some SQL query. In your example

var resultQuery = query.Where(q => !q.IsDeleted && predicate).ToList();

you are combining a lambda expression and a boolean check. The only way to avoid the double Where clauses is to create a helper function that returns a lambda expression for filtering which includes filtering for the IsDeleted flag and the predicate logic i.e.

 private System.Linq.Expressions.Expression<Func<T, bool>> filterPredicate(int n)
 {
     return q => !q.IsDeleted && q.Age > n; 
 }

Here we are assuming that

q.Age > n

is the logic of your predicate function. And then use the filter predicates like this:

var resultQuery = query.Where(filterPredicate(5)).ToList();

More about lambda expressions and expression trees you can read here https://learn.microsoft.com/en-us/dotnet/api/system.linq.expressions.expression-1?view=net-5.0

Upvotes: 1

dantey89
dantey89

Reputation: 2287

Instead, you could use custom extension methods and filter result using them:

public static class QueryExtensions
    {
        public static IQueryable<Image> NonDeleted(this IQueryable<Image> queryable)
        {
            return queryable.Where(x => !x.Deleted);
        }

        public static IQueryable<Image> LatestOnly(this IQueryable<Image> queryable)
        {
            return queryable.Where(x => x.CreateDate <= DateTime.UtcNow.AddDays(-7));
        }
    }

And then combine them in query:

var result = context
             .Images
             .NonDeleted()
             .LatestOnly()
             .ToList();

I like this approach cause it's clean and easy to read. You can also use interfaces in your entities and extension which use those interfaces to quickly filter items based on interfaces that implemented on entity. For example:

public interface ICreationDate{
  DateTime CreateDate {get;}
}

public class Image: ICreationDate{
  public DateTime CreateDate {get; private set;} = DateTime.UtcNow;
}

Then extension can be changed like this:

public static IQueryable<T> LatestOnly<T>(this IQueryable<T> queryable)
    where T : ICreationDate
        {
            return queryable.Where(x => x.CreateDate <= DateTime.UtcNow.AddDays(-7));
        }

This approach gives you more flexibility and reusability.

I know these all are too far from your original question, but it may bring you some alternative aproaches

Upvotes: 1

Related Questions