C# 使用数据库拦截器的实体框架软删除实现不工作

C# 使用数据库拦截器的实体框架软删除实现不工作,c#,asp.net,database,entity-framework,soft-delete,C#,Asp.net,Database,Entity Framework,Soft Delete,我已经使用以下教程实现了数据库软删除(将条目标记为已删除的布尔标志): 在我看来,这是一个非常好的实现,因为一旦设置了软删除,只需添加[SoftDelete(“IsDeleted”)]注释即可将其应用于模型。问题是到目前为止它还不起作用 消息来源似乎可靠,他们甚至发布了一个解决方案示例: 你能看看我的代码,以防我在将软删除应用到我的项目时出错吗 这就是模型: [SoftDelete("IsDeleted")] public class BC_Instance { public int I

我已经使用以下教程实现了数据库软删除(将条目标记为已删除的布尔标志):

在我看来,这是一个非常好的实现,因为一旦设置了软删除,只需添加
[SoftDelete(“IsDeleted”)]
注释即可将其应用于模型。问题是到目前为止它还不起作用

消息来源似乎可靠,他们甚至发布了一个解决方案示例:

你能看看我的代码,以防我在将软删除应用到我的项目时出错吗

这就是模型:

[SoftDelete("IsDeleted")]
public class BC_Instance
{
    public int ID { get; set; }
    public bool IsDeleted { get; set; }
}
ApplicationDbContext.cs:

namespace bcplatform2.Models
{
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }

        // Add a DbSet for each one of your Entities
        //public DbSet<VirtualGuest> VirtualGuests { get; set; }
        public DbSet<BC_Instance> BiocloudInstances { get; set; }

        static ApplicationDbContext()
        {
            Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
        }

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }

        protected new void OnModelCreating(DbModelBuilder modelBuilder)
        {
            var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
               "SoftDeleteColumnName",
               (type, attributes) => attributes.Single().ColumnName);

            modelBuilder.Conventions.Add(conv);
        }
    }
}
protected new void OnModelCreating(DbModelBuilder modelBuilder) {...}
SoftDeleteAttribute.cs:

namespace bcplatform2.Helpers
{
    public class SoftDeleteAttribute : Attribute
    {
        public SoftDeleteAttribute(string column)
        {
            ColumnName = column;
        }

        public string ColumnName { get; set; }

        public static string GetSoftDeleteColumnName(EdmType type)
        {
            MetadataProperty annotation = type.MetadataProperties
                .Where(p => p.Name.EndsWith("customannotation:SoftDeleteColumnName"))
                .SingleOrDefault();

            return annotation == null ? null : (string)annotation.Value;
        }
    }
}
SoftDeleteInterceptor.cs

我注意到
SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType)
找不到SoftDelete属性并返回null。但我不知道为什么。

namespace bcplatform2.Helpers
{
    public class SoftDeleteInterceptor : IDbCommandTreeInterceptor
    {
        public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
        {
            if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
            {
                var queryCommand = interceptionContext.Result as DbQueryCommandTree;
                if (queryCommand != null)
                {
                    var newQuery = queryCommand.Query.Accept(new SoftDeleteQueryVisitor());
                    interceptionContext.Result = new DbQueryCommandTree(
                        queryCommand.MetadataWorkspace,
                        queryCommand.DataSpace,
                        newQuery);
                }

                var deleteCommand = interceptionContext.OriginalResult as DbDeleteCommandTree;
                if (deleteCommand != null)
                {
                    var column = SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType);
                    if (column != null)
                    {
                        var setClauses = new List<DbModificationClause>();
                        var table = (EntityType)deleteCommand.Target.VariableType.EdmType;
                        if (table.Properties.Any(p => p.Name == column))
                        {
                            setClauses.Add(DbExpressionBuilder.SetClause(
                                    DbExpressionBuilder.Property(
                                        DbExpressionBuilder.Variable(deleteCommand.Target.VariableType, deleteCommand.Target.VariableName),
                                        column),
                                    DbExpression.FromBoolean(true)));
                        }

                        var update = new DbUpdateCommandTree(
                            deleteCommand.MetadataWorkspace,
                            deleteCommand.DataSpace,
                            deleteCommand.Target,
                            deleteCommand.Predicate,
                            setClauses.AsReadOnly(),
                            null);

                        interceptionContext.Result = update;
                    }
                }
            }
        }
    }
}
namespace bcplatform2.Helpers
{
公共类SoftDeleteInterceptor:IDbCommandTreeInterceptor
{
已创建公共无效树(DbCommandTreeInterceptionContext interceptionContext)
{
if(interceptionContext.OriginalResult.DataSpace==DataSpace.SSpace)
{
var queryCommand=interceptionContext.Result为DbQueryCommandTree;
if(queryCommand!=null)
{
var newQuery=queryCommand.Query.Accept(新的SoftDeleteQueryVisitor());
Result=new DbQueryCommandTree(
queryCommand.MetadataWorkspace,
queryCommand.DataSpace,
新查询);
}
var deleteCommand=interceptionContext.OriginalResult作为DbDeleteCommandTree;
if(deleteCommand!=null)
{
var column=SoftDeleteAttribute.GetSoftDeleteColumnName(deleteCommand.Target.VariableType.EdmType);
if(列!=null)
{
var setClaires=新列表();
变量表=(EntityType)deleteCommand.Target.VariableType.EdmType;
if(table.Properties.Any(p=>p.Name==column))
{
添加(DbExpressionBuilder.SetClause(
DbExpressionBuilder.Property(
DbExpressionBuilder.Variable(deleteCommand.Target.VariableType,deleteCommand.Target.VariableName),
柱),
DbExpression.FromBoolean(true));
}
var update=new DbUpdateCommandTree(
deleteCommand.MetadataWorkspace,
deleteCommand.DataSpace,
deleteCommand.Target,
deleteCommand.Predicate,
setClaires.AsReadOnly(),
无效);
Result=update;
}
}
}
}
}
}
IdentityConfig.cs

public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext>
{
    protected override void Seed(ApplicationDbContext context)
    {
        InitializeIdentityForEF(context);
        base.Seed(context);
    }

    //Create User=Admin@Admin.com with password=Admin@123456 in the Admin role        
    public static void InitializeIdentityForEF(ApplicationDbContext db)
    {
        //Initialize users and roles...
    }
}
公共类应用程序BinInitializer:DropCreateDatabaseIfModelChanges
{
受保护的重写无效种子(ApplicationDbContext上下文)
{
InitializeIdentityFore(上下文);
种子(上下文);
}
//创建用户=Admin@Admin.com带密码=Admin@123456在管理员角色中
公共静态void initializedEntityForef(ApplicationDbContext数据库)
{
//初始化用户和角色。。。
}
}

我觉得你的代码很好。也许有一个小小的错误正在破坏你的应用程序。你可以试试这个:

  • BC\u实例

  • 编辑
    OnModelCreating
    方法

    AttributeToTableAnnotationConvention<SoftDeleteAttribute, string> conv =
       new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
          "SoftDeleteColumnName",
          (type, attributes) => attributes.Single().ColumnName);
    
    modelBuilder.Conventions.Add(conv);
    //this will dynamically add the attribute to all models
    modelBuilder.Types().Configure(delegate(ConventionTypeConfiguration i)
    {
        i.HasTableAnnotation("SoftDeleteColumnName", Entity.G etSoftDeleteColumnName());
    });
    

  • 希望这有帮助

    ApplicationDbContext.cs中有一个错误:

    namespace bcplatform2.Models
    {
        public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
        {
            public ApplicationDbContext()
                : base("DefaultConnection", throwIfV1Schema: false)
            {
            }
    
            // Add a DbSet for each one of your Entities
            //public DbSet<VirtualGuest> VirtualGuests { get; set; }
            public DbSet<BC_Instance> BiocloudInstances { get; set; }
    
            static ApplicationDbContext()
            {
                Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
            }
    
            public static ApplicationDbContext Create()
            {
                return new ApplicationDbContext();
            }
    
            protected new void OnModelCreating(DbModelBuilder modelBuilder)
            {
                var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
                   "SoftDeleteColumnName",
                   (type, attributes) => attributes.Single().ColumnName);
    
                modelBuilder.Conventions.Add(conv);
            }
        }
    }
    
    protected new void OnModelCreating(DbModelBuilder modelBuilder) {...}
    
    您使用的是“new”而不是“override”,因此永远不会执行OnModelCreating(尝试添加断点以检查它)。因此,AttributeToTableAnnotationConvention永远不会运行,也永远不会添加实体注释

    改成

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {...}
    

    会成功的

    谢谢你的帮助。一个问题:在'i.HasTableAnnotation(“SoftDeleteColumnName”,Entity.GetSoftDeleteColumnName())行中,`->
    当前上下文中不存在名称实体
    。此外,我应该如何检查它是否有效。如果我直接查询数据库,我应该会看到删除记录,对吗?拦截器只应用于代码?在我的例子中,Entity是ModelStack继承的基类。看看@tede24的答案,这可能是正确的!如果重写,则不会调用原始的OnModelCreating,情况不应该是这样<另一方面,code>new使这两种方法都被调用。这是不正确的。您应该重写并调用base.OnModelCreating以委托给默认方法(如果需要)。只要在当前方法中设置一个断点并测试它是否停止,您就会看到它不会停止。抱歉,您完全正确。我误解了有关
    new
    vs
    override
    关键字的文档。谢谢,lotDelete标志应该是时间戳,而不是bools。