簡體   English   中英

使用Entity Framework 6支持SQL Server更改跟蹤

[英]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注冊攔截器。

值得注意的是,該框架將在每次INSERTUPDATEDELETE之前調用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查詢。 短期內更改跟蹤:

優點:

  • 輕量級
  • 設置非常簡單
  • 支持同步
  • 仍然是事務的一部分(如果事務失敗則回滾)
  • 沒有SQL代理依賴
  • 將捕獲在正常ORM更改操作之外完成的更改(代碼調用的存儲過程,所有更改源自應用程序之外)

缺點:

  • 不適合需要更多信息的審核
  • 慢一點,因為它同步完成(與CDC異步性質相反)

[原始答案]

一種方法是在“正常”更改中添加更改/跟蹤信息,並將所有更改/跟蹤信息放在單個事務中。

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

一個Nuget包似乎可以幫助你進行auding - TrackerEnabledDbContext

這種方法的一個優點是您可以輕松標記您的實體類型,以便不審計某些信息(實現接口或使用某些自定義屬性)。

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

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

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

另一種方法是使用服務器端(SQL) 更改數據捕獲 ,捕獲對啟用了此功能的表所做的所有更改。 CDC的一個重要方面是審計表結構發生變化時的行為。 有關更多信息,請閱讀本文

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM