很遗憾,Entity Framework 6 没有对 SQL Server 更改跟踪的内置支持。但是,它确实公开了拦截功能,使您能够在执行之前修改它生成的 SQL。虽然更改 ORM 生成的 SQL 需要谨慎且有充分的理由,但在某些情况下它绝对是合适的解决方案。
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 界面上没有大量出色的文档,但 this MSDN article 是一个不错的起点。