c# - EF 5 条件映射

标签 c# entity-framework asp.net-mvc-4

我在我的 MVC 应用程序中使用 EF 5 数据库优先方法。我所有的表都使用一个名为 Deleted 的字段,这是一个 bool 字段来标记记录已删除。

我试图摆脱每次查询数据库时都必须检查 Deleted == false 的要求。执行此操作的非常直接的方法是在 edmx 文件中使用条件映射,其中 EF 始终返回未删除的数据。这一切都很好。

但是做这个条件映射的问题是,当我想允许用户从他们的地址簿中删除一些记录,例如地址时,我无法访问 EF 中的 Delete 字段,因为我在条件中使用了它映射,因此我必须寻找另一个选项来允许用户删除记录。

我的想法是创建一个存储过程来处理删除查询并在我想删除记录时调用它。

有更好的方法吗?即使在条件映射中使用,是否可以使 Delete 字段可访问?

最佳答案

我有一个适用于 Soft Delete in Entity Framework Code First 的解决方案这可能会有所帮助。

关键是您要为每个希望能够软删除的模型添加一个鉴别器。在代码优先中,这样做是这样的:

modelBuilder.Entity<Foo>().Map(m => m.Requires("IsDeleted").HasValue(false));

这使得它对上下文不可见,因此您必须使用 sql 进行删除。

如果这相当于您在 Database First 中的“条件映射”,那么修改 sql 的一种方法是覆盖 SaveChanges 并从那里运行 sql:

public override int SaveChanges()
{
   foreach (var entry in ChangeTracker.Entries()
             .Where(p => p.State == EntityState.Deleted 
             && p.Entity is ModelBase))//I do have a base class for entities with a single 
                                       //"ID" property - all my entities derive from this, 
                                       //but you could use ISoftDelete here
    SoftDelete(entry);

    return base.SaveChanges();
}

private void SoftDelete(DbEntityEntry entry)
{
    var e = entry.Entity as ModelBase;
    string tableName = GetTableName(e.GetType());
    Database.ExecuteSqlCommand(
             String.Format("UPDATE {0} SET IsDeleted = 1 WHERE ID = @id", tableName)
             , new SqlParameter("id", e.ID));

    //Marking it Unchanged prevents the hard delete
    //entry.State = EntityState.Unchanged;
    //So does setting it to Detached:
    //And that is what EF does when it deletes an item
    //http://msdn.microsoft.com/en-us/data/jj592676.aspx
    entry.State = EntityState.Detached;
}

用于Get Table Name explained here的方法

这就是我以前做的方式。可能与您在 EF5 中的数据库优先方法无关,但我现在已经转向在存储过程中执行此操作。 EF6 代码首先生成 CreateStoredProcedure在迁移文件中调用。我将这些替换为 this.CreateDeleteProcedure("dbo.Foo_Delete", "[dbo].[Foos]"); - 这是对我自己的扩展方法的调用:

public static class MigrationExtensions
{
    internal static string DeleteSqlFormat
    {
        //I also hard delete anything deleted more than a day ago in the same table
        get { return "DELETE FROM {0} WHERE IsDeleted = 1 AND DATEADD(DAY, 1, DeletedAt) < GETUTCDATE(); UPDATE {0} SET IsDeleted = 1, DeletedAt = GETUTCDATE() WHERE ID = @ID;"; }
    }

    internal static void CreateDeleteProcedure(this DbMigration migration, string procName, string tableName)
    {
        migration.CreateStoredProcedure(
                        procName,
                        p => new
                        {
                            ID = p.Int(),
                        },
                        body:

                            string.Format(MigrationExtensions.DeleteSqlFormat, tableName)

                    );
    }

}

关于c# - EF 5 条件映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19246067/

相关文章:

c# - 创建一个 IEqualityComparer<IEnumerable<T>>

c# - 将枚举转换为字符串的最佳实践方法是什么?

jquery - 不引人注目的验证不适用于 MVC 4 中的 Textarea

javascript - mvc Javascript 文件在文件更改后不更新

asp.net - 哪里可以获得 MVC4 的源代码

c# - 使用 C# 从 MongoDB 中的文档中删除元素

c# - 两个相同的类在不同的库和一个项目中

entity-framework - 如何解决 AutoMapper 错误? (stackoverflow 异常!)

.net - 如何跨程序集将元数据与类定义分开?

c# - Parallel.Foreach 循环创建多个数据库连接会引发连接错误?