How can I combine BinaryExpression
and Expression<Func<dynamic / T, bool>>
?
For example:
void AddGlobalFilter<T>(Expression<Func<T, bool>> expr)
{
var parameter = Expression.Parameter(type, "t");
var member = Expression.Property(filter.Parameter, field);
var constant = Expression.Constant(null);
var body = Expression.Equal(member, constant);
var combine = Expression.AndAlso(body, expr);
}
I am trying to define global filter for Entity Framework (EF) Core. The problem is I must manually combine multiple filters.
One filter may be added in ModelBuilder
if model implements IDbDeleted
interface.
Another could be added manually for specific model. Basic idea is I have a list of all Expressions, and then combine them:
var expression = listExpressions.First();
foreach (var second in listExpressions.Skip(1))
{
expression = Expression.AndAlso(expression, second);
}
var lambdaExpression = Expression.Lambda(expression, parameter);
modelBuilder.Entity(item.Key).HasQueryFilter(lambdaExpression);
Of course I get error (first is from Expression.Equal
and second from t => t...
):
The filter expression 't => t => (Not(t. ...
Edited: code looks something like that:
[Table("MyEntities")]
public class DbMyEntity : IDeleted
{
public string Name { get; set; }
public DateTime? DateTimeDeleted { get; set; }
}
public interface IDeleted
{
DateTime? DateTimeDeleted { get; set; }
}
public class MyContext : IdentityDbContext
{
private Dictionary<Type, List<Expression>> dict = new Dictionary<Type, List<Expression>>();
private Dictionary<Type, ParameterExpression> dictParameter = new Dictionary<Type, ParameterExpression>();
private ParameterExpression GetParameter(Type type)
{
if (!this.dictParameter.ContainsKey(type))
{
this.dictParameter.Add(type, Expression.Parameter(type, "t"));
}
return this.dictParameter[type];
}
private void AddToDict(Type type, Expression expr)
{
if (!this.dict.ContainsKey(type))
{
this.dict.Add(type, new List<Expression>());
this.GetParameter(type); //Just to create ParameterExpression if not exists.
}
this.dict[type].Add(expr);
}
private void AddToDict<T>(Expression<Func<T, bool>> expr)
{
this.AddToDict(typeof(T), expr);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
if (typeof(IDeleted).IsAssignableFrom(entity.ClrType))
{
var member = Expression.Property(this.GetParameter(entity.ClrType), "DateTimeDeleted");
var constant = Expression.Constant(null);
var body = Expression.Equal(member, constant);
this.AddToDict(entity.ClrType, body);
}
}
//This is done in another project in same solution. See comment bellow.
this.AddToDict<DbMyEntity>(t => t.Name == null || t.Name == "Something");
//foreach (var builderType in allDllModules)
//{
// if (builderType != null && builderType != typeof(ICustomModelBuilder))
// {
// var builder = (ICustomModelBuilder)Activator.CreateInstance(builderType);
// builder.Build(modelBuilder);
// }
//}
foreach (var item in this.dict)
{
var expression = item.Value.First();
foreach (var second in item.Value.Skip(1))
{
expression = Expression.AndAlso(expression, second);
}
var lambdaExpression = Expression.Lambda(expression, this.dictParameter[item.Key]);
modelBuilder.Entity(item.Key).HasQueryFilter(lambdaExpression);
}
}
}