Pues si, digo bien con sorpresa, porque hasta ahora yo no era consciente de que esta fuera a ser una de las nuevas características de EF 6, de hecho si miramos el roadmap veremos que no estaba contemplada. Pero por lo que sea ya tenemos aquí los primeros commits relacionados con la posibilidad de implementar mecanismos de intercepción en la nueva versión de Entity Framework. Aunque seguramente cambiarán ciertas cosas hasta la versión final, no me puedo resistir a enseñaros alguna pincelada.
Interception
La clase estática Interception representa por ahora el punto dónde podemos agregar y quitar nuestros interceptores. En realidad, esto me ha chocado un poco porque creía que era un patrón obsoleto como el uso de Database en anteriores versiones, y creo que va a cambiar, aunque en el tablero de preguntas del proyecto hay una pregunta abierta que espero que respondan. Esta clase es tan simple como vemos a continuación.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">class</span> Interception { <span class="rem">/// <summary></span> <span class="rem">/// Registers a new <see cref="IDbInterceptor" /> to receive notifications. Note that the interceptor</span> <span class="rem">/// must implement some interface that extends from <see cref="IDbInterceptor" /> to be useful.</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="interceptor">The interceptor to add.</param></span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> AddInterceptor(IDbInterceptor interceptor) { } <span class="rem">/// <summary></span> <span class="rem">/// Removes a registered <see cref="IDbInterceptor" /> so that it will no longer receive notifications.</span> <span class="rem">/// If the given interceptor is not registered, then this is a no-op.</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="interceptor">The interceptor to remove.</param></span> <span class="kwrd">public</span> <span class="kwrd">static</span> <span class="kwrd">void</span> RemoveInterceptor(IDbInterceptor interceptor) { } <span class="rem">/// <summary></span> <span class="rem">/// This is the entry point for dispatching to interceptors. This is usually only used internally by</span> <span class="rem">/// Entity Framework but it is provided publicly so that other code can make sure that registered</span> <span class="rem">/// interceptors are called when operations are performed on behalf of EF. For example, EF providers</span> <span class="rem">/// a may make use of this when executing commands.</span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">static</span> Dispatchers Dispatch { } } |
Como se puede ver, en realidad, lo que nos ofrece es un mecanismo para agregar y quitar interceptores, pensado en enchufar los mismos solamente en ciertas partes del trabajo o momentos determinados. De hecho la nueva característica de scaffolding de los procedimientos almacenados se basa en esta infraestructura. A mayores de esto, vemos como un interceptor no es más que cualquier clase que implemente IDbInterceptor, por suerte, a nosotros ya nos ofrecen una clase base de la que partir llamada DbInterceptor, que será la que usemos por norma general.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
<span class="kwrd">public</span> <span class="kwrd">class</span> DbInterceptor : IDbCommandInterceptor, IDbCommandTreeInterceptor { <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> DbCommandTree TreeCreated(DbCommandTree commandTree, DbInterceptionContext interceptionContext) { <span class="kwrd">return</span> commandTree; } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> NonQueryExecuting(DbCommand command, DbInterceptionContext interceptionContext) { } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">int</span> NonQueryExecuted(DbCommand command, <span class="kwrd">int</span> result, DbInterceptionContext interceptionContext) { <span class="kwrd">return</span> result; } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> ReaderExecuting(DbCommand command, CommandBehavior behavior, DbInterceptionContext interceptionContext) { } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> DbDataReader ReaderExecuted( DbCommand command, CommandBehavior behavior, DbDataReader result, DbInterceptionContext interceptionContext) { <span class="kwrd">return</span> result; } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> ScalarExecuting(DbCommand command, DbInterceptionContext interceptionContext) { } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">object</span> ScalarExecuted(DbCommand command, <span class="kwrd">object</span> result, DbInterceptionContext interceptionContext) { <span class="kwrd">return</span> result; } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> AsyncNonQueryExecuting(DbCommand command, DbInterceptionContext interceptionContext) { } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> Task<<span class="kwrd">int</span>> AsyncNonQueryExecuted(DbCommand command, Task<<span class="kwrd">int</span>> result, DbInterceptionContext interceptionContext) { <span class="kwrd">return</span> result; } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> AsyncReaderExecuting(DbCommand command, CommandBehavior behavior, DbInterceptionContext interceptionContext) { } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> Task<DbDataReader> AsyncReaderExecuted( DbCommand command, CommandBehavior behavior, Task<DbDataReader> result, DbInterceptionContext interceptionContext) { <span class="kwrd">return</span> result; } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> AsyncScalarExecuting(DbCommand command, DbInterceptionContext interceptionContext) { } <span class="rem">/// <inheritdoc /></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> Task<<span class="kwrd">object</span>> AsyncScalarExecuted(DbCommand command, Task<<span class="kwrd">object</span>> result, DbInterceptionContext interceptionContext) { <span class="kwrd">return</span> result; } } |
Como podéis ver, hay muchos métodos en los que nos podemos enganchar, tanto para llamadas síncronas como asíncronas, así como a ciertores pre-post procesos, como por ejemplo en la ejecución de comandos. Un hola mundo, podría ser el siguiente, donde sacamos por la consola las consultas de lectura ejecutadas por EF:
1 2 3 4 5 6 7 8 9 10 |
<span class="kwrd">public</span> <span class="kwrd">class</span> TracerInterceptor :DbInterceptor { <span class="kwrd">public</span> <span class="kwrd">override</span> DbDataReader ReaderExecuted(DbCommand command, System.Data.CommandBehavior behavior, DbDataReader result, DbInterceptionContext interceptionContext) { Console.WriteLine(<span class="str">"CommandText:{0}"</span>,command.CommandText); <span class="kwrd">return</span> result; } } |
Feedback
Estoy seguro que todo el equipo va a necesitar feedback de esta nueva característica, que os gusta, que no, que necesitáis que no tengáis etc. por eso me gustaría pediros a todos que os animéis a pasar por el portal del producto y dejar vuestras necesidades / recomendaciones etc…
Saludos
Unai
Es lo malo de escribir posts con todo en desarrollo, que se quedan desactualizados de un día para otro
En las dos últimas dos entradas he hablado sobre el nuevo bloque introducido en Entity Framework 6 para