很遗憾,Entity Framework 6没有内置对SQL Server更改跟踪的支持。然而,它提供了拦截功能,使您能够在执行之前修改生成的SQL。虽然更改ORM生成的SQL应该谨慎并且只有在必要时才应该这样做,但绝对存在适用的情况。
EF6公开了IDbCommandInterceptor类型,它为您提供了钩子来访问整个查询管道。您只需要实现此接口并将拦截器注册到EF即可。
值得注意的是,框架将在每个INSERT、UPDATE和DELETE之前调用NonQueryExecuting,这使得它成为您连接更改跟踪的好地方。
以一个简单的例子为例,考虑以下拦截器:
public class ChangeTrackingInterceptor : IDbCommandInterceptor
{
private byte[] GetChangeTrackingContext()
{
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;
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文章是一个不错的起点。