2012-08-13 54 views
2

我正在使用Linq to SQL,並且每當更新特定記錄時都想插入到表中。Linq to SQL:在更新到另一個實體期間動態插入

所以可以說我有Table1Table2,每當Table1一個記錄被更新我想插入新記錄到Table2

目前,我有工作代碼,讓我更新Table1幾個領域時,它被更新,這已經通過爲UpdateTable1函數創建一個局部的方法來實現,像這樣:

partial void UpdateTable1(Table1 instance) 
{ 
    //update some fields 
    this.ExecuteDynamicUpdate(instance); 
} 

這效果很好,而且非常實用,我想用它來確保在更新Table1時始終在Table2中創建新記錄。順便說一下,這主要是爲了記錄目的。

原來這就是我想下一步該怎麼做:

partial void UpdateTable1(Table1 instance) 
{ 
    //update some fields 
    this.ExecuteDynamicUpdate(instance); 
    this.ExecuteDynamicInsert(instance.ConvertToTable2()); 
} 

(我使用的是擴展方法在這裏創建基於Table實例表2記錄)

的問題是我得到出現以下錯誤:

The operation cannot be performed for the entity because it is not being change tracked.

任何想法如何使這項工作?

回答

3

忘記我不可靠的解決方法(如果必須,請參閱編輯歷史記錄),我發現了一個更可靠的方法來完成此任務!

首先,忘記使用部分方法這一目的(例如UpdateTable1的問題)這不工作這麼好,除非你正在修改的數據僅用於實例記錄。所以我保留這些部分方法僅用於我需要更新實例中的相關字段。

執行此操作的方法是覆蓋部分DataContext類中的SubmitChanges方法。這將允許插入/更新/刪除任何表記錄,然後允許默認SubmitChanges處理(並因此鎖定此功能)。

裏面的覆蓋您可以訪問使用this.GetChangeSet()當前DataContext變更集,從這個你可以循環所有的變化和執行所需的任何額外的工作表(例如添加日誌記錄)。

對於下面的例子,讓我們假設我有一個標準的數據庫表稱爲Table1,我有一個匹配的日誌表稱爲Table1Log,我要錄製Table1Table1Log內的任何變化,從而記錄表包含所有相同的字段作爲原始文件,但擴展到存儲DateTime(更改時間)和LogType(即添加/編輯/刪除)。

這裏是我的最終代碼的重要組成部分:

partial class MyDataContext 
{ 

    public override void SubmitChanges(System.Data.Linq.ConflictMode failureMode) 
    { 

     var set = this.GetChangeSet();//get a list of all pending changes 

     foreach (var item in set.Inserts) 
     { 
      AddLog(item, LogType.Add); 
     } 
     foreach (var item in set.Updates) 
     { 
      AddLog(item, LogType.Edit); 
     } 
     foreach (var item in set.Deletes) 
     { 
      AddLog(item, LogType.Delete); 
     } 

     base.SubmitChanges(failureMode);//allow the DataContext to perform it's default work (including your new log changes) 

    } 

    public void AddLog(object item, LogType logType) 
    { 

     //some painful type testing, so feel free to refactor this as you wish 
     if(item is Table1) 
     { 
      var log = (item as Table1).ToLog(logType);//ToLog() is an extension method (one for each type) 
      this.Table1_Logs.InsertOnSubmit(log);//add the log record ready to be submitted 
     } 
     else if(item is Table2) 
     { 
      //same again 
     } 
     //...repeat for each table class type 

    } 

} 

注意:對的if/else類型的測試另一種可能是found here。實際上,我在代碼中使用了它,它的工作原理非常好,我懷疑是否有性能優勢,但是當您需要切換50多種類型時,它確實有助於保持可讀性。

0

那麼,插入,你真的只有兩個選項。好吧,其實3。

您可以將觸發器添加到數據庫。我們使用它來進行跟蹤工作。我們有一個更新觸發器,用於插入帶有更改的記錄。這是有效的,而且容易。

如果你想使用LINQ到SQL你唯一的選擇是插入表格按照您的指定,即db.Table2s.InsertOnSubmit(...)然後提交更改。

另一種選擇,假設你的日誌表和你的實體之間有一個外鍵關係,就是通過LINQ to SQL分配這個實體關係,那麼你可以簡單地插入你的日誌實體,而不需要引用數據上下文。

partial void UpdateEntity(Entity instance) 
{ 
    instance.Logs.Add(instance.createLogEntry()); 
} 

以這種方式完成後,您將不需要對數據上下文的引用,但根據您的情況,這可能不是一個選項。

+0

由於需要記錄來自系統的額外數據,觸發器並不好。觸發器將無法解決這個問題。你的選擇涉及到關係已經發生在我身上,但是我試過了(就像你發佈的那樣)並且代碼運行良好,但之後沒有新的日誌記錄 - 你真的看到了這個工作嗎? – musefan 2012-08-13 15:42:26

+0

我已經看到了實體方法的工作。它基本上取決於你何時調用它。如果你在調用'DataContext.SubmitChanges()'之前調用它,那麼它應該可以工作,因爲添加到實體集合類似於調用'log.MyForeignKeyId = x; db.Logs.InsertOnSubmit(x);'但是如果在初次調用'db.SubmitChanges()'後調用它,那麼它將不會被添加,您將不得不再次調用'SubmitChanges'。 – 2012-08-13 16:48:07

+0

解決了它!如果您有興趣,請查看我的答案;) – musefan 2012-08-14 10:38:04

相關問題