简体   繁体   English

EF 5条件映射

[英]EF 5 Conditional Mapping

I'm using EF 5 Database first approach in my MVC application. 我在我的MVC应用程序中使用EF 5数据库第一种方法。 all of my tables uses a Field called Deleted which is a boolean field to mark a record is deleted. 我的所有表都使用一个名为Deleted的字段,这是一个标记记录被删除的布尔字段。

I'm trying to get rid of the requirement of having to check Deleted == false every time I query my database. 我试图摆脱每次查询我的数据库时必须检查Deleted == false的要求。 The very straightforward way of doing this is to use a conditional mapping in the edmx file where EF always return data that are not deleted. 这种非常简单的方法是在edmx文件中使用条件映射,其中EF始终返回未删除的数据。 That's all good. 这一切都很好。

But the problem of doing this condition mapping is that, when I want to allow the user to delete some record for eg Address from their address book I don't have access to Delete field from EF as I used it in the conditional mapping and therefore I have to look for another option to allow user to delete a record. 但是,这个条件映射的问题在于,当我想允许用户从地址簿中删除例如地址的某些记录时,我无法访问EF中的删除字段,因为我在条件映射中使用它,因此我必须寻找另一个允许用户删除记录的选项。

The way I thought is to create a stored proc that handle the delete query and call it when I want to delete the record. 我想的方法是创建一个处理删除查询的存储过程,并在我想删除记录时调用它。

Is there a better way of doing this? 有没有更好的方法呢? Is it possible to make the Delete field accessible even it is used in the conditional mapping? 是否可以使删除字段可访问,即使它在条件映射中使用?

I have a working solution for Soft Delete in Entity Framework Code First that may help. 我有一个有效的解决方案,可以帮助实体框架Code First中的软删除

The key is that you add a discriminator to every model that you want to be able to soft delete. 关键是你要为每个你想要软删除的模型添加一个鉴别器。 In code first that is done like this: 在代码中首先这样做:

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

This makes it invisible to the context and therefore you have to do the deletes using sql. 这使得它对上下文不可见,因此您必须使用sql执行删除操作。

If this is the equivalent of your "conditional mapping" in Database First then one way to modify the sql is to override SaveChanges and run sql from there: 如果这相当于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;
}

Method used to Get Table Name explained here 用于获取表名的方法在此解释

That is the way I used to do it. 这就是我以前的做法。 Probably irrelevant to your Database First approach in EF5, but I have now moved to doing it in stored procedures. 可能与EF5中的Database First方法无关,但我现在已经开始在存储过程中执行此操作。 EF6 Code First generates CreateStoredProcedure calls in Migration files. EF6 Code First在迁移文件中生成CreateStoredProcedure调用。 I replace these with this.CreateDeleteProcedure("dbo.Foo_Delete", "[dbo].[Foos]"); 我用this.CreateDeleteProcedure("dbo.Foo_Delete", "[dbo].[Foos]");替换它们this.CreateDeleteProcedure("dbo.Foo_Delete", "[dbo].[Foos]"); - which is a call to my own extension method: - 这是对我自己的扩展方法的调用:

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)

                    );
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM