In EF Core 7, I am able to filter included collections like
var users = _context.Users.Include(x => x.Roles.Where(y => y.IsDeleted == false)).ToList();
I would like to make an extension, which simplify this include to this:
var users = _context.Users.Include(x => x.Roles, true).ToList();
where true means withoutDeleted.
So, I need to merge two expressions, In my case
Expression<Func<IDbEntityDelete, bool>> expression1 = x => !x.IsDeleted;
Expression<Func<User,ICollection<Role>>> expression2 = x => x.Roles;
First one is constant expression and second one is an expression comming as argument in my extension.
public static IIncludableQueryable<TEntity, TCollection> Include<TEntity, TCollection>(this IQueryable<TEntity> query, Expression<Func<TEntity, TCollection>> navigationExpression, bool withoutDeleted) where TEntity : class, IDbEntityDelete
{
}
Could you please help me to Combine navigationExpression with expression1?
So the result lambda is exactly x => x.Roles.Where(y => y.IsDeleted == false)?
Thank you!
This simple extension implementation should add soft delete filter for Include
:
public static class IncludeExtensions
{
public static IIncludableQueryable<TEntity, IEnumerable<TItem>> Include<TEntity, TItem>(
this IQueryable<TEntity> query,
Expression<Func<TEntity, IEnumerable<TItem>>> navigationExpression,
bool withoutDeleted
)
where TEntity : class
where TItem : class, IDbEntityDelete
{
if (!withoutDeleted)
{
return query.Include(navigationExpression);
}
// let the compiler to generate filter stuff.
Expression<Func<IEnumerable<TItem>, IEnumerable<TItem>>> filterTemplate = q => q.Where(e => !e.IsDeleted);
// replacing template parameter with navigationExpression
var filterBody = ReplacingExpressionVisitor.Replace(filterTemplate.Parameters[0], navigationExpression.Body, filterTemplate.Body);
var filterLambda = Expression.Lambda<Func<TEntity, IEnumerable<TItem>>>(filterBody, navigationExpression.Parameters);
return query.Include(filterLambda);
}
}