c# - Admite el seguimiento de cambios de SQL Server con Entity Framework 6
sql-server entity-framework (2)
Tengo un modelo Entity Framework 6 Code First generado a partir de una base de datos de SQL Server existente. La base de datos utiliza el seguimiento de cambios de SQL Server, por lo que para todas las operaciones de manipulación de datos generadas por EF, quiero configurar el contexto de seguimiento de cambios para distinguirlos de los cambios realizados por otros procesos externos. Esto se hace generalmente en T-SQL como
WITH CHANGE_TRACKING_CONTEXT (@source_id) UPDATE <table>...
Lo único en lo que puedo pensar es anteponer la cláusula sql anterior al SQL generado por EF. A pesar de que aparece, querer modificar el SQL generado por un ORM es cuestionable. Aun así, incluso si quiero, no sé dónde se puede hacer. ¿Puede EF la Intercepción de Comandos cumplir el propósito?
La pregunta es específicamente sobre el uso de la función de seguimiento de cambios de SQL Server junto con EF (no el seguimiento de cambios de EF). En términos de EF, la pregunta es solo sobre la modificación programática del SQL generado por EF
Desafortunadamente, Entity Framework 6 no tiene soporte incorporado para el seguimiento de cambios de SQL Server. Sin embargo, expone las capacidades de intercepción que le permiten modificar el SQL que genera antes de la ejecución. Si bien cambiar el SQL que genera un ORM es algo que debe hacerse con cuidado y solo con una buena razón, hay casos en los que es la solución adecuada.
EF6 expone el tipo IDbCommandInterceptor
, que le proporciona IDbCommandInterceptor
el IDbCommandInterceptor
consulta. Simplemente necesita implementar esta interfaz y registrar su interceptor con EF.
En particular, el marco llamará a NonQueryExecuting
antes de cada INSERT
, UPDATE
y DELETE
, lo que lo convierte en un excelente lugar para enganchar su seguimiento de cambios.
Como un ejemplo simple, considere este interceptor:
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)
{
}
}
Cuando EF genera cualquier consulta que cambie el estado de la base de datos, llamará a este método antes de ejecutar la consulta. Esto le da la oportunidad de inyectar su contexto de seguimiento de cambios personalizado utilizando SQL estándar.
Para registrar su interceptor con EF, simplemente llame a DbInterception.Add
en algún lugar de su código de inicio:
var changeTrackingInterceptor = new ChangeTrackingInterceptor();
DbInterception.Add(changeTrackingInterceptor);
No hay una gran cantidad de documentación en la interfaz IDbCommandInterceptor
, pero este artículo de MSDN es un buen lugar para comenzar.
[Editar después de la aclaración de OP]
Creo que es más fácil configurar el seguimiento de cambios en el servidor y no meterse con las consultas de EF. Cambio de seguimiento en breve poner:
Pros:
- ligero
- la configuración es bastante fácil
- soporte para sincronización
- sigue siendo parte de la transacción (revertida si la transacción falla)
- sin dependencia del Agente SQL
- detectará los cambios realizados fuera de la operación normal de cambio de ORM (procedimientos almacenados llamados por su código, todos los cambios originados fuera de su aplicación)
Contras:
- No aptos para auditorías que requieran más información.
- un poco más lento, porque se realizó de forma síncrona (en oposición a la naturaleza asíncrona de los CDC)
[respuesta original]
Una forma es agregar información de cambio / seguimiento a lo largo de sus cambios "normales" y tenerlos todos dentro de una sola transacción.
Puede anular el método SaveChanges
y agregar el código para la información de seguimiento. La referencia de ChangeTracker le permite encontrar todas las entidades que tienen un estado determinado (agregado, actualizado, eliminado, sin modificar) y, por lo tanto, también puede guardar el tipo de cambio realizado. Un ejemplo completo de trabajo se proporciona here .
Parece que hay un paquete Nuget para ayudarle con la audición - TrackerEnabledDbContext
Una ventaja de este enfoque es que marca fácilmente los tipos de entidad, de modo que no se audita alguna información (ya sea que implemente una interfaz o use algún atributo personalizado).
Otra ventaja es que puede ajustar el seguimiento de cambios aún más especificando explícitamente los atributos de seguimiento en sus propiedades.
Una desventaja que veo es que las transacciones serán más largas y el bloqueo de algunas tablas será más largo, lo que posiblemente conlleve problemas de rendimiento (esto depende en gran medida de la cantidad de transacciones por período de tiempo).
Además, esta solución solo detectará cambios en su código de contexto (EF) y no en otros cambios que se realicen directamente en la base de datos o mediante procedimientos almacenados (independientemente del hecho de que se los llame desde un proceso externo o EF).
Otro enfoque es utilizar la captura de datos de cambio del lado del servidor (SQL) que captura todos los cambios realizados en las tablas que tienen habilitada esta función. Un aspecto importante de los CDC es el comportamiento cuando se modifica la estructura de la tabla auditada. Para más información lea este artículo .
El enfoque del lado del servidor tiene dos ventajas principales:
- Es más rápido porque se hace de forma asíncrona.
- más confiable, si los cambios de datos provienen de varias fuentes (manualmente, ETL, procedimiento almacenado, etc.).