2016-11-30 151 views
14

我有一個實體框架6 Code First模型從現有的SQL Server數據庫中生成。數據庫正在使用SQL Server Change Tracking,因此對於從EF生成的所有數據操作操作,我想設置Change Tracking上下文以區別於其他外部進程所做的更改。這通常是在T-SQL完成爲
WITH CHANGE_TRACKING_CONTEXT (@source_id) UPDATE <table>...支持使用實體框架的SQL Server更改跟蹤6

我能想到的是前面加上上面的SQL子句由EF生成的SQL的唯一的事。雖然看起來,想要修改由ORM生成的SQL本身是有問題的。儘管如此,即使我想,我也不知道它可以在哪裏完成。 EF命令攔截能達到目的嗎?

這個問題特別是關於SQL Server的更改跟蹤功能與EF一起使用(而不是EF的更改跟蹤)。在EF而言,問題是隻有通過編程EF

+0

不確定我的問題是否正確 - 從我推斷的情況來看,只要通過EF完成更新,就想執行chnage_tracking。也許你可以爲你的更新/添加/刪除存儲特效(有你需要的跟蹤),然後將它映射到EF實體。更多細節在這裏 - http://www.entityframeworktutorial.net/entityframework6/code-first-insert-update-delete-stored-procedure-mapping.aspx。讓我知道如果我看錯了你的問題.. – Developer

回答

0

[OP的澄清後編輯]

我認爲這是比較容易set up Change Tracking on the server side和不亂用EF查詢生成的SQL修改。更改跟蹤不久就把:

優點:

  • 輕量級
  • 的設置是很容易的
  • 同步
  • 交易仍然部分(回滾如果交易失敗)
  • 支持
  • 無SQL代理依賴關係
  • 將捕獲更改側正常ORM改變操作(存儲過程的代碼調用,所有的改變源自您的應用程序之外)

缺點:

  • 不適合審覈需要更多的信息
  • 慢一點,因爲它是同步完成的(相對於CDC的異步性質)

[原始回答]

一種方法是根據「正常」更改添加更改/跟蹤信息,並將其全部範圍限定在單個事務中。

您可以覆蓋您的DbContextSaveChanges方法並添加跟蹤信息的代碼。通過ChangeTracker參考,您可以查找具有特定狀態(添加,更新,刪除,未修改)的所有實體,從而還可以保存執行的更改類型。提供一個完整的工作示例here

一個NuGet包似乎是有幫助你與auding - TrackerEnabledDbContext

這種方法的優點是,可以輕鬆地標記你的實體類型,所以有些信息不審覈(無論是實現一個接口或使用一些自定義屬性)。

另一個優點是,您可以通過在屬性上明確指定跟蹤屬性來更好地調整更改跟蹤。

我看到的一個缺點是事務會更長,鎖定某些表會更長,可能會導致性能問題(這在很大程度上取決於每個時間段的事務數)。

此外,此解決方案僅捕獲您的上下文代碼(EF)的更改,而不會直接針對數據庫或通過存儲過程執行的其他更改(無論它們是從外部進程還是EF調用) 。

另一種方法是使用服務器端(SQL)Change Data Capture,它捕獲對啓用了此功能的表所做的所有更改。 CDC的一個重要方面是審計表結構發生變化時的行爲。欲瞭解更多信息,請閱讀this article

服務器端方法有兩個主要優點:

  • 是更快,因爲它是異步完成
  • 更可靠,如果數據的變化來自各種來源(手動,ETL,存儲過程等)。
+0

這個問題是專門關於SQL Server更改跟蹤,讓我更新問題的清晰度 –

+0

我想我不能更清楚,更改跟蹤已被使用... –

5

不幸的是,實體框架6沒有內置的對SQL Server變更跟蹤的支持。但是,它確實暴露了攔截功能,使您可以修改它在執行之前生成的SQL。在更改ORM生成的SQL時,應該小心翼翼地完成這些操作,並且只有在有充分理由的情況下才會這樣做,但絕對有這種情況是適當的解決方案。

EF6公開IDbCommandInterceptor類型,該類型爲您提供了整個查詢管道的鉤子。你簡單的需要實現這個接口並用EF註冊你的攔截器。

值得注意的是,該框架將在每個INSERT,UPDATEDELETE之前調用NonQueryExecuting,這使其成爲您鎖定變更跟蹤的好地方。

作爲一個簡單的例子,考慮這個攔截:

public class ChangeTrackingInterceptor : IDbCommandInterceptor 
{ 
    private byte[] GetChangeTrackingContext() 
    { 
     // TODO: Return the appropriate change tracking context data 
     return new byte[] { 0, 1, 2, 3 }; 
    } 

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
    { 
     command.CommandText = "WITH CHANGE_TRACKING_CONTEXT (@change_tracking_context)\r\n" + command.CommandText; 

     // Create the varbinary(128) parameter 
     var parameter = command.CreateParameter(); 
     parameter.DbType = DbType.Binary; 
     parameter.Size = 128; 
     parameter.ParameterName = "@change_tracking_context"; 
     parameter.Value = GetChangeTrackingContext(); 
     command.Parameters.Add(parameter); 
    } 

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
    { 
    } 

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 
    { 
    } 

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 
    { 
    } 

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
    { 
    } 

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
    { 
    } 
} 

當EF產生改變數據塊的狀態的任何查詢時,它會執行查詢之前調用此方法。這使您有機會使用標準SQL注入您的自定義更改跟蹤上下文。

要註冊與EF你的攔截器,只需撥打DbInterception.Add地方在你的啓動代碼:

var changeTrackingInterceptor = new ChangeTrackingInterceptor(); 
DbInterception.Add(changeTrackingInterceptor); 

這裏沒有一噸IDbCommandInterceptor界面上大的文檔,但this MSDN article是一個良好的開端。

+0

This是我試圖讓它發揮作用的方式,但無法做到。事實上,攔截器無法運行,然後因健康狀況不佳而不得不離開工作崗位。一回到工作崗位並留下反饋意見,我會盡快再試一次,所以到目前爲止,這還沒有經過我的考驗 –