[英]Support SQL Server change tracking with Entity Framework 6
我有一個從現有SQL Server數據庫生成的Entity Framework 6 Code First模型。 數據庫正在使用SQL Server更改跟蹤,因此對於從EF生成的所有數據操作操作,我想設置更改跟蹤上下文,以區別於其他外部進程所做的更改。 這通常在T-SQL中完成
WITH CHANGE_TRACKING_CONTEXT (@source_id) UPDATE <table>...
我唯一能想到的是將上面的sql子句添加到EF生成的SQL中。 雖然看來,想要修改ORM生成的SQL本身就值得懷疑。 盡管如此,即使我想,我也不知道它可以在哪里完成。 EF Command Interception可以達到目的嗎?
問題是關於SQL Server的更改跟蹤功能與EF一起使用(不是EF的更改跟蹤)。 就EF而言,問題只是以編程方式修改EF生成的SQL
不幸的是,Entity Framework 6沒有內置的SQL Server Change Tracking支持。 但是,它確實暴露了攔截功能,使您能夠在執行之前修改它生成的SQL。 在更改SQL時,ORM生成的內容是應該仔細進行的,並且只有充分的理由,絕對是合適的解決方案。
EF6公開了IDbCommandInterceptor
類型,它為您提供了整個查詢管道的鈎子。 您只需要實現此接口並使用EF注冊攔截器。
值得注意的是,該框架將在每次INSERT
, UPDATE
和DELETE
之前調用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生成任何更改DB狀態的查詢時,它將在執行查詢之前調用此方法。 這使您有機會使用標准SQL注入自定義更改跟蹤上下文。
要使用EF注冊攔截器,只需在啟動代碼中的某處調用DbInterception.Add
:
var changeTrackingInterceptor = new ChangeTrackingInterceptor();
DbInterception.Add(changeTrackingInterceptor);
關於IDbCommandInterceptor
接口的文檔並不多,但這篇MSDN文章是一個很好的起點。
[OP澄清后編輯]
我認為在服務器端設置更改跟蹤更容易,而不是弄亂EF查詢。 短期內更改跟蹤:
優點:
缺點:
[原始答案]
一種方法是在“正常”更改中添加更改/跟蹤信息,並將所有更改/跟蹤信息放在單個事務中。
您可以覆蓋DbContext
的SaveChanges
方法並添加跟蹤信息的代碼。 ChangeTracker引用允許您查找具有特定狀態(添加,更新,刪除,未修改)的所有實體,從而能夠保存所執行的更改類型。 這里提供了一個完整的工作示例。
一個Nuget包似乎可以幫助你進行auding - TrackerEnabledDbContext
這種方法的一個優點是您可以輕松標記您的實體類型,以便不審計某些信息(實現接口或使用某些自定義屬性)。
另一個優點是,您可以通過在屬性上明確指定跟蹤屬性來進一步微調更改跟蹤。
我看到的一個缺點是事務將更長並且鎖定某些表將更長,可能導致性能問題(這在很大程度上取決於每個時間段的事務數)。
此外,此解決方案將僅捕獲您的上下文代碼(EF)中的更改,而不會捕獲直接針對數據庫或通過存儲過程執行的其他更改(無論是從外部進程還是EF調用它們)。
另一種方法是使用服務器端(SQL) 更改數據捕獲 ,捕獲對啟用了此功能的表所做的所有更改。 CDC的一個重要方面是審計表結構發生變化時的行為。 有關更多信息,請閱讀本文 。
服務器端方法有兩個主要優點:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.