2010-09-29 146 views
4

我的應用程序中有多個業務對象(C#,Winforms,WinXP)。當用戶在UI上執行某些操作時,這些對象中的每一個都會被應用程序的不同部分修改和更新。每次修改後,我需要首先檢查已更改的內容,然後記錄對對象所做的更改。記錄這個目的是爲了創建一個對應用程序中正在進行的活動的全面跟蹤。捕獲對象屬性的更改

這些對象中包含許多包含其他對象的名單,這嵌套可以幾個層次深。對於任何解決方案的兩個主要要求是

  1. 捕捉儘可能準確地
  2. 保持性能成本最低的變化。

如業務對象:

public class MainClass1 
{ 
    public MainClass1() 
    { 
     detailCollection1 = new ClassDetailCollection1(); 
     detailCollection2 = new ClassDetailCollection2(); 
    } 

    private Int64 id; 
    public Int64 ID 
    { 
     get { return id; } 
     set { id = value; } 
    } 

    private DateTime timeStamp; 
    public DateTime TimeStamp 
    { 
     get { return timeStamp; } 
     set { timeStamp = value; } 
    } 

    private string category = string.Empty; 
    public string Category 
    { 
     get { return category; } 
     set { category = value; } 
    } 

    private string action = string.Empty; 
    public string Action 
    { 
     get { return action; } 
     set { action = value; } 
    } 

    private ClassDetailCollection1 detailCollection1; 
    public ClassDetailCollection1 DetailCollection1 
    { 
     get { return detailCollection1; } 
    } 

    private ClassDetailCollection2 detailCollection2; 
    public ClassDetailCollection2 DetailCollection2 
    { 
     get { return detailCollection2; } 
    } 

    //more collections here 
} 

public class ClassDetailCollection1 
{ 
    private List<DetailType1> detailType1Collection; 
    public List<DetailType1> DetailType1Collection 
    { 
     get { return detailType1Collection; } 
    } 

    private List<DetailType2> detailType2Collection; 
    public List<DetailType2> DetailType2Collection 
    { 
     get { return detailType2Collection; } 
    } 
} 

public class ClassDetailCollection2 
{ 
    private List<DetailType3> detailType3Collection; 
    public List<DetailType3> DetailType3Collection 
    { 
     get { return detailType3Collection; } 
    } 

    private List<DetailType4> detailType4Collection; 
    public List<DetailType4> DetailType4Collection 
    { 
     get { return detailType4Collection; } 
    } 
} 

//more other Types like MainClass1 above... 

我可以假設,我將有機會獲得舊值和對象的新值。

在這種情況下,我能想到的2種方式,試圖做到這一點沒有被告知哪些已明確改變。

  1. 使用反射和迭代通的對象的所有屬性和比較 那些與老對象的相應屬性 。日誌 已更改的任何屬性。這 方法似乎更加靈活, ,我不會擔心,如果任何 新屬性添加到任何 對象。但它也似乎表現沉重。
  2. 在setter中記錄所有對象的所有屬性的更改。 除了這個將 需要我改變很多代碼的事實外,它似乎更加蠻力。這將是 維護繁重和不靈活,如果 某人更新任何對象 類型。但這種方式也可能是 性能與光,因爲我不會 需要檢查哪些改變和日誌 性質被改變什麼。

建議以上述方法更好的方法和/或改進,歡迎

+0

我寫了一個reflction爲基礎,但預編譯單個對象(對)比較器這樣回答。所以它可以做得相對便宜。打開弓,不能看 - 但會嘗試稍後找到它。 – 2010-09-29 15:20:14

回答

2

我可能無法給你一個很好的答案,但我要告訴你的是,在絕大多數情況下,選項1是不是一個很好的答案。在我們的項目中,我們正在處理一個非常類似的反射式「圖形漫步者」;似乎是在當時是個好主意,但它是一個噩夢,有以下原因:

  • 你知道對象改變了,但沒有關於運作反射「變化處理」一流的知識水平高上面的物體,你可能不知道爲什麼。如果這些信息對您很重要,您必須將其交給更改處理程序,大多數情況下都可以通過域對象上的字段或屬性進行更改,從而要求更改您的域並向域傳授有關業務邏輯的知識。
  • 更改可能會影響多個對象,但可能不希望在每個級別記錄更改;例如,當新貸款被批准時,客戶可能不希望在日誌中看到借款人尚未償還貸款的變化,但他們確實希望看到由於合併而導致的變化。在這些情況下管理有關登錄的規則需要更改處理類才能知道更多的結構,而不僅僅是一個對象,這可以很快地使變更處理對象變得非常大而且非常脆弱。
  • 您的圖形漫步者的要求可能比您知道的要多;如果您的對象圖包含反向引用或交叉引用,那麼Walker必須知道它的位置,最簡單的綜合方法是保存處理對象的列表,並檢查當前對象與處理對象之前處理的對象(使反向追蹤N^2操作)。它也不能考慮對圖中對象的更改,當持久保存最高級別(不是「級聯」的引用)時,該對象不會被保留。 NHibernate使您能夠插入自己的圖形漫步者並遵守映射中的級聯rukles,這有助於實現,但如果您使用的是自己的DAL,或者您想將更改記錄到對象NHibernate不會級聯,你將不得不自己設置這一切。
  • 處理程序中的一段邏輯可能做出需要更新「父」對象(可能更新計算字段)的更改。現在,如果更改對另一部分更改處理邏輯感興趣,則必須返回並重新評估更改的對象。
  • 如果您有需要創建和持續新對象的邏輯,則必須執行以下兩項操作之一;將新對象附加到圖形的某處(可能或不可能被walker拾取),或者將新對象保存在自己的事務中(如果使用的是ORM,則該對象不能從另一個對象引用對象帶有「級聯」設置的圖表會導致首先保存)。
  • 最後,在漫遊圖形和查找特定對象的「處理程序」方面具有高度反射性,將複雜的樹傳遞到此類框架中可以保證在應用程序中減速。

我想你會爲自己省下很多麻煩,如果你跳過「更改處理」反射模式,包括在審計日誌或任何持久性預邏輯的創造「的工作單元」你」通過一組「審計記錄器」重新在業務層進行。這使得進行更改的邏輯可以使用諸如Command或Strategy之類的算法選擇模式來告訴審計框架究竟發生了什麼樣的改變,因此它可以選擇將生成所需日誌消息的記錄器。

+0

我最終採用了第二種方法的混合體。我現在保存所有創建和刪除的更改,並查詢數據庫以查看比較和記錄更改的對象以前的狀態。 – EndlessSpace 2010-11-17 20:44:41

3

我在幾年前開發這樣的系統。這個想法是跟蹤對象的變化並將這些變化存儲在數據庫中,例如對象的版本控制。

最好的辦法是叫Aspect-Oriented Programming,或AOP。你向設置者和獲取者注入「建議」(實際上所有的方法執行,獲取者和設置者都只是特殊的方法),允許你「截取」對象所採取的行動。查看.NET AOP解決方案的Spring.NETPostSharp

+0

+1,我想你可以添加一個IsDirty setter作爲建議。有沒有辦法爲每個屬性做到這一點,而不必通過整個屬性列表並附加屬性?有沒有辦法在命名空間中爲所有類執行此操作? – user420667 2013-07-24 19:54:14