2013-10-08 54 views
4

我在我的MVC應用程序中使用EF 5數據庫的第一種方法。我所有的表都使用一個名爲Deleted的字段,這是一個布爾字段來標記記錄被刪除。EF 5條件映射

我試圖擺脫每次查詢我的數據庫時必須檢查Deleted == false的要求。這樣做的直接方法是在edmx文件中使用條件映射,其中EF總是返回未被刪除的數據。這很好。

但做這種條件映射的問題是,當我想允許用戶從他們的地址簿中刪除例如地址的某些記錄時,我無法從EF中刪除字段,因爲我在條件映射,因此我不得不尋找另一個選項來允許用戶刪除一條記錄。

我認爲的方式是創建一個存儲過程,處理刪除查詢並在我想刪除記錄時調用它。

有沒有更好的方法來做到這一點?即使它在條件映射中使用,是否可以使Delete字段可訪問?

回答

14

我有一個工作解決方案Soft Delete in Entity Framework Code First可能有所幫助。

關鍵是,您可以爲您希望能夠軟刪除的每個模型添加一個鑑別器。在第一個代碼是這樣完成的:

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

這使得它無形的背景下,因此您可以使用SQL做刪除。

如果這是在數據庫中你的「條件映射」的同義的第一,然後修改SQL一個辦法就是從那裏覆蓋的SaveChanges和運行SQL:用於Get Table Name explained here

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; 
} 

方法那是我過去這樣做的方式。可能與EF5中的數據庫優先方法無關,但我現在已經開始使用存儲過程。 EF6 Code First在遷移文件中生成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) 

        ); 
    } 

} 
+0

+1非常好的解決方案。 –

+0

這就是我一直在尋找的詞,「軟刪除」。是的,這對於代碼來說似乎是一個很好的解決方案。很可能,我將在存儲過程中創建一個動態查詢,並在edmx中使用存儲過程映射,並將我創建的存儲過程映射到Delete。所以當我在上下文中調用Delete時,它會自動調用我自動映射的Delete存儲過程。 – Amila

+0

令人印象深刻的是,在尋找工作解決方案後,我找到了一個。在讓GetTableName工作時有一些小問題,你在另一篇文章中發佈的版本需要一些小的調整來編譯。但這並沒有改變這個事實,即這種軟刪除方法的確像一種魅力。 –