EF Core:具有阴影属性和查询过滤器的软删除 [英] EF Core: Soft delete with shadow properties and query filters

查看:122
本文介绍了EF Core:具有阴影属性和查询过滤器的软删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个界面来尝试进行软删除,混合阴影属性和查询过滤器。

 公共接口IDeletableEntity {} 

然后在我的模型构建器中

  builder.Model.GetEntityTypes() 
.Where(entityType => typeof(IDeletableEntity).IsAssignableFrom(entityType.ClrType))
.ToList()
.ForEach(entityType =>
{
builder.Entity(entityType.ClrType).Property< Boolean>( IsDeleted);
builder.Entity(entityType.ClrType).HasQueryFilter(e => EF.Property< Boolean>(e, IsDeleted )== false);
});

但是带有查询过滤器的行无法编译。我得到的错误是无法将lambda表达式转换为'lambda表达式'类型,因为它不是委托类型



如果执行此操作,它将起作用。

  builder.Entity< MyEntity>()。HasQueryFilter(m => EF.Property< Boolean>(m, IsDeleted)==假); 

有什么方法可以做到这一点?



在此先要感谢具有IDeletableEntity的接口,而不必这样做,



在此先感谢,

解决方案

非泛型 EntityTypeBuilder的HasQueryFilter (与通用的 EntityTypeBuilder< TEntity> 相对)几乎不可用,因为没有简单的方法来创建预期的 LambdaExpression



一种解决方案是使用 Expression 类方法手动构建lambda表达式:

  .ForEach(entityType => 
{
builder.Entity(entityType.ClrType)。属性< Boolean>( IsDeleted);
var参数= Expression.Parameter(entityType.ClrType, e);
var body = Expression.Equal(
Expression.Call(typeof (EF),nameof(EF.Property),new [] {typeof(bool)},参数,Expression.Constant( IsDeleted))),
Expressio n.Constant(false));
builder.Entity(entityType.ClrType).HasQueryFilter(Expression.Lambda(body,parameter));
});

另一种方法是使用原型表达式

  Expression< Func< object,bool>>过滤器= 
e => EF.Property bool(e, IsDeleted)== false;

并使用参数替换器将参数绑定为实际类型:

  .ForEach(entityType => 
{
builder.Entity(entityType.ClrType).Property< Boolean>( IsDeleted) ;
var参数= Expression.Parameter(entityType.ClrType, e);
var主体= filter.Body.ReplaceParameter(filter.Parameters [0],parameter);
构建器。 Entity(entityType.ClrType).HasQueryFilter(Expression.Lambda(body,parameter));
});

其中 ReplaceParameter 是自定义帮助程序之一我用于表达式树操作的扩展方法:

  public静态局部类ExpressionUtils 
{
public静态表达式ReplaceParameter(此表达式表达式,ParameterExpression源,表达式目标)=>
new ParameterReplacer {Source =源,Target =目标} .Visit(expr);

类ParameterReplacer:System.Linq.Expressions.ExpressionVisitor
{
public ParameterExpression Source;
公众表达目标;
保护的覆盖表达式Expression VisitParameter(ParameterExpression node)=>节点==源?目标:节点;
}
}

但我认为最自然的解决方案是移动通用方法中的配置代码,并通过反射进行调用。例如:

 静态void ConfigureSoftDelete< T>(模型构建器构建器)
其中T:类,IDeletableEntity
{
builder.Entity< T>()。Property< Boolean>( IsDeleted);
builder.Entity< T>()。HasQueryFilter(e => EF.Property< bool>(e, IsDeleted)== false);
}

,然后

  .ForEach(entityType => GetType()
.GetMethod(nameof(ConfigureSoftDelete),BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(entityType.ClrType )
.Invoke(null,new object [] {builder})
);


I've created an interface to try to do a soft delete, mixing shadow properties and query filters. But it's not working.

public interface IDeletableEntity {}

And then in my model builder

 builder.Model.GetEntityTypes()
                .Where(entityType => typeof(IDeletableEntity).IsAssignableFrom(entityType.ClrType))
                .ToList()
                .ForEach(entityType =>
                {
                    builder.Entity(entityType.ClrType).Property<Boolean>("IsDeleted");
                    builder.Entity(entityType.ClrType).HasQueryFilter(e => EF.Property<Boolean>(e, "IsDeleted") == false);
                });

But the line with the query filter doesn't compile. The error I got is "cannot convert lambda expression to type 'lambda expression' because it is not a delegate type"

If I do this it's working.

builder.Entity<MyEntity>().HasQueryFilter(m => EF.Property<Boolean>(m, "IsDeleted") == false);

there are any way to do this? It's in order to have an Interface with IDeletableEntity and not have to do it, in every Entity that I want to use a soft delete Entity

Many thanks in advance,

解决方案

HasQueryFilter of the non generic EntityTypeBuilder (as opposed to the generic EntityTypeBuilder<TEntity>) is almost unusable because there is no easy way to create the expected LambdaExpression.

One solution is to build the lambda expression by hand using the Expression class methods:

.ForEach(entityType =>
{
    builder.Entity(entityType.ClrType).Property<Boolean>("IsDeleted");
    var parameter = Expression.Parameter(entityType.ClrType, "e");
    var body = Expression.Equal(
        Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(bool) }, parameter, Expression.Constant("IsDeleted")),
    Expression.Constant(false));
    builder.Entity(entityType.ClrType).HasQueryFilter(Expression.Lambda(body, parameter));
});

Another one is to use a prototype expression

Expression<Func<object, bool>> filter = 
    e => EF.Property<bool>(e, "IsDeleted") == false;

and use a parameter replacer to bind the parameter with actual type:

.ForEach(entityType =>
{
    builder.Entity(entityType.ClrType).Property<Boolean>("IsDeleted");
    var parameter = Expression.Parameter(entityType.ClrType, "e");
    var body = filter.Body.ReplaceParameter(filter.Parameters[0], parameter);
    builder.Entity(entityType.ClrType).HasQueryFilter(Expression.Lambda(body, parameter));
});

where ReplaceParameter is one of the custom helper extension method I'm using for expression tree manipulation:

public static partial class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expr, ParameterExpression source, Expression target) =>
        new ParameterReplacer { Source = source, Target = target }.Visit(expr);

    class ParameterReplacer : System.Linq.Expressions.ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node) => node == Source ? Target : node;
    }
}

But most natural solution in my opinion is to move the configuration code in a generic method and call it via reflection. For instance:

static void ConfigureSoftDelete<T>(ModelBuilder builder)
    where T : class, IDeletableEntity
{
    builder.Entity<T>().Property<Boolean>("IsDeleted");
    builder.Entity<T>().HasQueryFilter(e => EF.Property<bool>(e, "IsDeleted") == false);
}

and then

.ForEach(entityType => GetType()
    .GetMethod(nameof(ConfigureSoftDelete), BindingFlags.NonPublic | BindingFlags.Static)
    .MakeGenericMethod(entityType.ClrType)
    .Invoke(null, new object[] { builder })
);

这篇关于EF Core:具有阴影属性和查询过滤器的软删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆