2009-12-21 12 views
9

我正在處理數據庫,其中設計者決定用IsHistorical位列標記每個表。沒有考慮適當的建模,並且我無法更改模式。使用EntityFramework軟刪除(IsHistorical列)

當開發與導航屬性相互作用的CRUD屏幕時,這會造成一些摩擦。我不能簡單地拿一個產品,然後編輯它的EntityCollection我不得不手動寫IsHistorical檢查到處都是,它讓我發瘋。

附加也太可怕了,因爲到目前爲止,我已經寫了所有的人工檢查,看是否加法只是軟刪除添加重複的實體,我可以只需撥動IsHistoric所以不是。

的三個選項,我考慮的是:

  1. 修改T4模板包括IsHistorical檢查和同步。

  2. 截取缺失和在ObjectContext的增加,切換IsHistorical列,然後同步的對象的狀態。

  3. 訂閱AssociationChanged事件並在那裏切換IsHistorical列。

有沒有人有這方面的經驗或可以推薦最無痛的方法?

注:是的,我知道,這是不好的造型。我讀過關於軟件刪除的相同文章。它很臭,我必須處理這個要求,但我這樣做。我只想要處理軟刪除的最無痛的方法,而不必爲我的數據庫中的每個導航屬性編寫相同的代碼。

注#2盧克萊德的答案在技術上是正確的,儘管強迫你成爲一個非常糟糕的人類ORM,無圖形模式。問題在於,現在我需要從圖中剔除所有「已刪除」對象,然後在每一個對象上調用Delete方法。那真的不會爲我節省那麼多手工禮儀編碼。現在我正在收集已刪除的對象並循環播放,而不是編寫手動IsHistoric檢查。

+3

我感覺到你的痛苦,並會仔細監視這個線程。希望你得到答案! –

+1

你爲什麼說它真的很差/差?你能解釋更多嗎? – LukLed

回答

5

正如我敢肯定,你知道,有不會是一個偉大的解決這一問題,當你不能修改架構。既然你不喜歡的庫選項(雖然,我不知道,如果你不是隻是有點倉促將其關閉),這裏是我能拿出最好的:

  1. 手柄ObjectContext.SavingChanges
  2. 當該事件觸發時,拖網通過ObjectStateManager尋找處於刪除狀態的對象。如果它們具有IsHistorical屬性,請設置該屬性,並將該對象的狀態更改爲已修改。

當涉及到關聯/關係時,這可能會變得棘手,但我認爲它或多或少都是您想要的。

8

我在我的代碼中使用通用存儲庫。你可以不喜歡它:

public class Repository<T> : IRepository<T> where T : EntityObject 
{ 
    public void Delete(T obj) 
    { 
     if (obj is ISoftDelete) 
      ((ISoftDelete)obj).IsHistorical = true 
     else 
      _ctx.DeleteObject(obj); 
    } 

List()方法將通過IsHistorical太過濾。

編輯:

ISoftDelete接口:

public interface ISoftDelete 
{ 
    bool IsHistorical { get; set; } 
} 

實體類可以很容易地標記爲ISoftDelete,因爲它們是部分的。部分類定義需要單獨的文件中加入:

public partial class MyClass : EntityObject, ISoftDelete 
{ 

} 
+0

如果'T'是一個'EntityObject',那它又如何從接口'ISoftDelete'繼承?那不是多重繼承(在.Net中不允許)? –

+0

@Yaakow埃利斯:這是允許的。您可以從一個類繼承,但您可以根據需要實現多個接口。 'ISoftDelete'是界面。 – LukLed

+0

換句話說,'ISoftDelete'定義了一個屬性:'IsDeleted'。沒有一行代碼表示「class X」(本例中爲「T」)從「ISoftDelete」繼承。但是,如果'X'具有'IsDeleted'屬性,那麼通過定義,任何實例'var i = new X()'將返回(我是ISoftDelete)爲true?所以'X'實現了接口(通過遵循其契約),即使它不從接口繼承?這是否使用反射?做這樣的事會大大影響性能嗎? –

0

我使用的存儲庫模式也有類似的代碼LukLed的,但我使用反射來看看是否IsHistorical屬性是有(因爲它是一個在命名約定一致):

public class Repository<TEntityModel> where TEntityModel : EntityObject, new() 
{ 
     public void Delete(TEntityModel entity) 
     { 
      // see if the object has an "IsHistorical" flag 
      if (typeof(TEntityModel).GetProperty("IsHistorical") != null); 
      { 
       // perform soft delete 
       var historicalProperty = entity.GetType().GetProperty("IsHistorical"); 
       historicalProperty.SetValue(entity, true, null); 
      } 
      else 
      { 
       // perform real delete 
       EntityContext.DeleteObject(entity); 
      } 

      EntityContext.SaveChanges();     
     } 
} 

用法則簡單地說:

using (var fubarRepository = new Repository<Fubar>) 
{ 
    fubarRepository.Delete(someFubar); 
} 

當然,在實踐中,您將擴展該通過傳遞,而不是一個實例化實體PK允許刪除等