Tal y como hicimos en la entrega anterior vamos a ir poniendo ejemplos completos de algunos de los puntos de extensibilidad que tenemos en Entity Framework 6. En esta ocasión hablaremos de operaciones de migración, algo que ya comentamos en alguna entrada anterior, como esta. Tal y como explicamos en su momento, esto nos permite cubrir de forma personalizada con operaciones que no tengamos out of box.
Como en la entrada anterior, el código se puede descargar desde:
https://github.com/unaizorrilla/ef.contrib
Creación y borrado de vistas
A pesar de que esto suele ser habitual, estas opciones no las tenemos por defecto como operaciones de migración, por lo que son unos buenos candidatos de ejemplo. A continuación podemos ver el código de la operación CreateViewOperation.
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 |
<span class="rem">/// <summary></span> <span class="rem">/// Represent a create view in database</span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">class</span> CreateViewOperation :MigrationOperation { <span class="rem">/// <summary></span> <span class="rem">/// The view name</span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">string</span> ViewName { get; <span class="kwrd">private</span> set; } <span class="rem">/// <summary></span> <span class="rem">/// The view body sql</span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">string</span> BodySql { get; <span class="kwrd">private</span> set; } <span class="rem">/// <summary></span> <span class="rem">/// Create a new instance</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="viewName">the view name to create</param></span> <span class="rem">/// <param name="bodySql">the view body sql </param></span> <span class="kwrd">public</span> CreateViewOperation(<span class="kwrd">string</span> viewName, <span class="kwrd">string</span> bodySql) :<span class="kwrd">base</span>(<span class="kwrd">null</span>) { Check.NotEmpty(viewName,<span class="str">"viewName"</span>); Check.NotEmpty(bodySql,<span class="str">"bodySql"</span>); <span class="kwrd">this</span>.ViewName = viewName; <span class="kwrd">this</span>.BodySql = bodySql; } <span class="rem">/// <inheritdoc/></span> <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> IsDestructiveChange { get { <span class="kwrd">return</span> <span class="kwrd">false</span>; } } <span class="rem">/// <inheritdoc/></span> <span class="kwrd">public</span> <span class="kwrd">override</span> MigrationOperation Inverse { get { <span class="kwrd">return</span> <span class="kwrd">new</span> DropViewOperation(ViewName); } } } |
La operación de borrado es también bastante sencilla:
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 |
<span class="rem">/// <summary></span> <span class="rem">/// Represent a drop view operation</span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">class</span> DropViewOperation :MigrationOperation { <span class="rem">/// <summary></span> <span class="rem">/// Get the view name to drop</span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">string</span> ViewName { get; <span class="kwrd">private</span> set; } <span class="rem">/// <summary></span> <span class="rem">/// Create a new View</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="viewName">the view name to drop</param></span> <span class="kwrd">public</span> DropViewOperation(<span class="kwrd">string</span> viewName) :<span class="kwrd">base</span>(<span class="kwrd">null</span>) { Check.NotEmpty(viewName, <span class="str">"viewName"</span>); ViewName = viewName; } <span class="rem">/// <inheritdoc/></span> <span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> IsDestructiveChange { get { <span class="kwrd">return</span> <span class="kwrd">true</span>; } } } |
Bien, ahora que ya tenemos creadas las operaciones solamente queda registrarlas en nuestro generador, que crearemos para darle soporte, tal y como se ve:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<span class="rem">/// <summary></span> <span class="rem">/// Extented Sql Server Migrations Sql Generator with more</span> <span class="rem">/// operations.</span> <span class="rem">/// <remarks></span> <span class="rem">/// For set this migrations sql generator you need register it in</span> <span class="rem">/// your DbMigrationsConfiguration{TContext} using the method </span> <span class="rem">/// SetSqlGenerator</span> <span class="rem">/// <example></span> <span class="rem">/// SetSqlGenerator("System.Data.SqlClient", new AdvancedSqlServerMigrationSqlGenerator());</span> <span class="rem">/// </example></span> <span class="rem">/// </remarks></span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">class</span> ExtendedSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator { <span class="rem">/// <inheritdoc/></span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Generate(MigrationOperation migrationOperation) { <span class="kwrd">this</span>.Generate((dynamic)migrationOperation); } } |
Si observa, hay un pequeño truco para no hacer “feas” conversiones de nuestras operaciones y ejecutar código en función de la que sea, y consiste en utilizar el tipo dynamic, gracias al cual podremos redirigir al generador de la operación que necesitemos…
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 |
<span class="rem">/// <summary></span> <span class="rem">/// Extented Sql Server Migrations Sql Generator with more</span> <span class="rem">/// operations.</span> <span class="rem">/// <remarks></span> <span class="rem">/// For set this migrations sql generator you need register it in</span> <span class="rem">/// your DbMigrationsConfiguration{TContext} using the method </span> <span class="rem">/// SetSqlGenerator</span> <span class="rem">/// <example></span> <span class="rem">/// SetSqlGenerator("System.Data.SqlClient", new AdvancedSqlServerMigrationSqlGenerator());</span> <span class="rem">/// </example></span> <span class="rem">/// </remarks></span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> <span class="kwrd">class</span> ExtendedSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator { <span class="rem">/// <inheritdoc/></span> <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> Generate(MigrationOperation migrationOperation) { <span class="kwrd">this</span>.Generate((dynamic)migrationOperation); } <span class="rem">/// <summary></span> <span class="rem">/// Generate a SQL to create a new view in database</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="createViewOperation">The operation to produce sql for.</param></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> Generate(CreateViewOperation createViewOperation) { <span class="kwrd">using</span> (var writer = Writer()) { writer.WriteLine(<span class="str">"CREATE VIEW {0} AS {1};"</span>,createViewOperation.ViewName,createViewOperation.BodySql); <span class="kwrd">this</span>.Statement(writer); } } <span class="rem">/// <summary></span> <span class="rem">/// Generate a SQL to drop a existing view in database</span> <span class="rem">/// </summary></span> <span class="rem">/// <param name="dropViewOperation">The operation to produce sql for.</param></span> <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> Generate(DropViewOperation dropViewOperation) { <span class="kwrd">using</span> (var writer = Writer()) { writer.WriteLine(<span class="str">"DROP VIEW {0} "</span>, dropViewOperation.ViewName); <span class="kwrd">this</span>.Statement(writer); } } } |
Para finalizar, ahora que tenemos nuestras operaciones y nuestro nuevo generador, solamente nos queda registrarlo…
1 2 3 4 5 6 7 8 9 10 11 |
<span class="kwrd">public</span> <span class="kwrd">class</span> Configuration :DbConfiguration { <span class="kwrd">public</span> Configuration() { AddMigrationSqlGenerator(<span class="str">"System.Data.SqlClient"</span>, () => { <span class="kwrd">return</span> <span class="kwrd">new</span> ExtendedSqlServerMigrationSqlGenerator(); }); } } |
Como se imaginará hay muchas más operaciones que podríamos construir para nuestras migraciones, cosas como el manejo de permisos, collation son algunas de las otras operaciones que tiene en el código de ejemplo que se hace referencia al principio del post.
Saludos
unai