【发布时间】:2018-07-24 11:08:27
【问题描述】:
如何组合BinaryExpression 和Expression<Func<dynamic / T, bool>>?
例如:
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);
}
我正在尝试为实体框架 (EF) 核心定义 global filter。问题是我必须manually combine multiple filters。
如果模型实现了IDbDeleted接口,则可以在ModelBuilder中添加一个过滤器。
可以为特定型号手动添加另一个。基本思想是我有一个所有表达式的列表,然后将它们组合起来:
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);
当然会出错(第一个来自Expression.Equal,第二个来自t => t...):
过滤表达式 't => t => (Not(t. ...
已编辑:代码看起来像这样:
[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);
}
}
}
【问题讨论】:
-
您能分享一下您当前代码的minimal reproducible example 吗?您的“完整”代码远不能编译
-
@CamiloTerevinto 已修复。
-
我正要回答,然后我看到了this。将
ReplaceExpressionVisitor与一个小改动结合起来:不要将body添加到字典中,而是添加var asLambda = Expression.Lambda(body, parameter);,使其最终成为Expression<Func<T, bool>>
标签: c# lambda entity-framework-core expression-trees entity-framework-core-2.1