EF vNext- Migrations 0.7.0.0

Las dos últimas entradas de este blog trataban sobre una de las novedades ( una de las importantes ) que traerá la próxima version de EF llamada Migrations. Ayer mismo, sacaron de forma publica una nueva revisión ( aún en version alfa, 0.7.0.0)  que presenta algunas novedades interesantes que me gustaría comentar aquí. Lógicmente no volveremos a hacer los walkthrough de los post anteriores ( por supuesto puede también revisar el blog del grupo de ADO.NET con sus propias guias), sino que solamente vermos algunas de las novedades introducidas.

Puerta de entrada para introducir datos con la migración

Lo primero que llama la atención con esta nueva versión es que la clase Settings, creada automáticamente cuando se agrega el paquete de migraciones, además de las opciones anteriores para establecer los generadores a utilizar nos proporciona un método para realizar un Seed de los datos.

 

    public class Settings : DbMigrationContext<CRMUnitOfWork>
    {
        public Settings()
        {
            AutomaticMigrationsEnabled = false;
            SetCodeGenerator<CSharpMigrationCodeGenerator>();
            AddSqlGenerator<SqlConnection, SqlServerMigrationSqlGenerator>();
        }
        protected override void Seed(CRMUnitOfWork context)
        {
            if (!context.Customers.Any())
            {
                context.Customers.Add(new Customer() { FirstName = "Unai" });
            }
            base.Seed(context);
        }   
    }

Este método Seed se ejecuta automáticamente cada vez que se hace una migración a la ultima versión. Bueno, aunque esto, aún parece que esta pillado con pinzas, sobre todo porque habría que discutir como afectan las migraciones hacia atrás con respecto a los datos etc… Es decir, parece que con todo lo que tenga que ver con Data Motion aún hay mucho por jugar. Veremos en las siguientes versiones que cariz toma esto.

 

Update-Database –Verbose

El nuevo flag –Verbose nos permite ver en nuestro Package Manager la información del SQL a generar para realizar la actualización de la base de datos después de una migración. Así por ejemplo si ejecutamos este comando podríamos ver cosas como las que podemos observar en la figura de la derecha.Untitled

 

Downgrades

 

En esta versión ya empezamos a tener la posibilidad de deshacer migraciones o situarnos en alguna migración en concreto, algo que ellos llaman downgrades. Supongamos que estamos trabajando con este paquete y realizamos por ejemplo dos migraciones. La inicial de nuestro proyecto, First, y después una llamada AddNotesProperty. Pues bien, esta segunda migración nos generaría un código como podría ser el siguiente:

 

    public partial class AddNotesProperty : DbMigration
    {
        public override void Up()
        {
            AddColumn("Customers", "Notes", c => c.String());
        }
        
        public override void Down()
        {
            DropColumn("Customers", "Notes");
        }
    }

En este pequeño fragmento podemos ver como tenemos un método para “deshacer” la migración, en nuestro casi algo tan simple como eliminar la columna previamente creada en la tabla Customers. Ahora,

si quisiéramos movernos por ejemplo a la versión inicial de la base de datos podríamos ejecutar el siguiente comando: Update-Database –TargetMigration:First.  Esto es realmente importante si por ejemplo nos queremos mover a una versión de código determinada y tenemos una base de datos por ejemplo posterior. Gracias a que todas las migraciones las tenemos disponibles como código dentro de la carpeta Migrations podemos realizar esta tarea sin dificultad ninguna.El flag –TargetMigration tiene un argumento especial que es 0 y nos permite movernos directamente a la primera migración.

 

Untitled2

 

 

 

Notas:

Aunque en esta versión han arreglado la dependencia con SqlExpress, no se podía utilizar el paquete de migraciones sino se  disponia de una instancia con nombre .SQLEXPRESS ( o en su defecto un alias) aún hay cosas que serían deseables y que no están. Como por ejemplo la posibilidad de usar toda la artillería de migraciones fuera de Visual Studio o el uso de Data Motion.

 

Saludos

Unai

EF vNext-Migrations II

En la anterior entrega hemos visto como usar el nuevo paquete que a salido del equipo de Data Development en Redmon. En esta nueva entrada, intentaremos continuar con algunos detalles importantes que nos permitan comprender mejor con que estamos tratando.

 

Migraciones automáticas

Si recuerda, cada vez que ejecutamos una migración por medio del comando Add-Command se incorpora a nuestro proyecto el sacaffolding de la migración por medio de una clase de tipo DbMigration. En alguna ocasión, puede que no nos interese tener estos ficheros de scaffolding y simplemente ejecutar la migración. A este proceso, se le conoce como migración automática. Para mostrar esto partiremos del código de la anterior entrada y modificaremos nuestra clase Customer agregandole una nueva  propiedad.

    public class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public int Age { get; set; }
    }

Bien, ahora para actualizar nuestro esquema, solamente tenemos que ejecutar el comando Update-Database, sin necesidad de crear la migración. Para que esto funcione necesitamos establecer en la configuración de las migraciones, nuestra clase Settings, que habilite las migraciones automáticas, tal y como podemos ver en el siguiente fragmento.

    public class Settings : DbMigrationContext<CRMUnitOfWork>
    {
        public Settings()
        {
            AutomaticMigrationsEnabled = true;
            SetCodeGenerator<CSharpMigrationCodeGenerator>();
            AddSqlGenerator<SqlConnection, SqlServerMigrationSqlGenerator>();

            // Uncomment the following line if you are using SQL Server Compact 
            // SQL Server Compact is available as the SqlServerCompact NuGet package
            // AddSqlGenerator<System.Data.SqlServerCe.SqlCeConnection, SqlCeMigrationSqlGenerator>();
        }
    }

Si bien la actualización automática del esquema es util, puede llegar a ser necesario disponer del script de actualización en vez de la ejecución de la migración directamente. Para disponer de este script, solamente tenemos que agregar el flag Script al comando anterior. La siguientes lines T-SQL se corresponden a una nueva migración en la que se ha incluido una propiedad Address.

BEGIN TRANSACTION;
SET XACT_ABORT ON;
ALTER TABLE [Customers] ADD [Address] [nvarchar](max);
INSERT INTO [__MigrationHistory] (Migration, CreatedOn, Hash, Model) VALUES ('Automatic Migration', getdate(), 0x4EE620C904605E84D8F981B7A5B861D15FFB6BC5DB8F9B9945E924EB798B72A4, 0x1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F22FEC7BFF71F7CFC7BBC5B94E9655E3745B5FCECA3DDF1CE4769BE9C56B36279F1D947EBF67CFBE0A3DFE3E8374E1E9FCE16EFD29F34EDF6D08EDE5C369F7D346FDBD5A3BB779BE93C5F64CD78514CEBAAA9CEDBF1B45ADCCD66D5DDBD9D9D83BBBB3B777302F111C14AD3C7AFD6CBB658E4FC07FD79522DA7F9AA5D67E517D52C2F1BFD9CBE79CD50D317D9226F56D934FFECA3A74FBE282EEAAC253C9A8FD2E3B2C80887D77979FE9E08ED3C04421FD9AEA8B35342AABD7E73BDCAB9C3CF3E3A59376DB5C86BBF15B5FBBDF2EBE003FAE8655DADF2BABD7E959FEBBB67B38FD2BBE17B77BB2FDAD7BC77D03DFDB66CEFED7D94BE5897653629E983F3AC6CF28FD2D5A78F5EB7559D7F9E2F7322423E7B99B56D5E2FF16ECEE82B191EAD3EBD1D251EDEDDD90325EE66CB65D5325D7B8877D07C56D44D8B5F0DB6AFDB9AF8E5A3F459F12E9F3DCF9717EDDC62FC45F6CE7C42BF7E947EB52C88BDE8A5B65EE7FE08E5EFCD3D3FCF7E8E3A3E5D6445F943EFF5F8C28E7488216E00309BD579D3FC2C23FEF8AE939C8DF2444AE48BBCCD66599BFD48A4023459EF7D3B6BE63FA753457AB8CD0A2283D17FAFBE20D8ED97E7DFADEAB79D1993375EE76D475712B3B92E44338FAD1EED52A10BC46390181C9F7FA2C3B2037016E4AE9810636AEE0ED89AC75F64AB1551DCB33DFA49FA5A0CCFC9F6EBF737310B817177DA442C8DC5D6F6447C985DE49D6FA96BC29495EE531AF924030F9CCC16FD66B7992ED35777D6BAE2E7886FDEC0EFF2966F83DDE47620380A3EA3412D4894787C3A3AC264C8BEEACBAFA75999D511713EA9CAF56239A41236BDED192E1F88F7F1ED613953E483729FDE1E92DA161F8C7E747B186C297C08FCC17BBC6F0C4500C37CD887F3F86E676EBBECE3E9196DD951DC5D86BC15BB06FAE16B73ECA01962303731EDC6B77F76F8D6B30E3E10EFE31FF20CF5F46DB789EDDDEADD8E7E7DACBA2E50C23CFEAEC3DF537ED2E4A394887459CCA0F85E5F376DBE18A3C1F8F52F2A4FCA82C6EB1A7C912D8BF3BC69DF546F73042FA49BBF7EE4608D7BD3CCCAFFB7860F05867FA357F39ECE64CFED5F5E66F5749ED55B8BECDD9DF7F56DBBAEFC07010BDCF30F82E4B9DC4CC4F7A451C7E17E0F54FEBFE144FFAC3096A7C7BE61B2F51CDA9E23356076BA12BCC9A7157DF4D947B349450310443D6FF8F62EEF4D1E6FACA36FC225EEABE2C777FD0CCDE3A779535C3810C8D72CF3298CA9036ADA9C2DCF2B33BF344A1F23D3A43BFD8AFF71DD16E7D9B4A5AFA724431CFEFC6456AE59BE27F9EC6CF9E5BA5DADDBE3A6C91793F2DA1FEFE3BB9BFB67BF3FC4F9F1972B7607BE8921109A050D21FF72F9645D94338BF7B33EFB0F81006BAA4C115614FE11B88B6B0BE945B5BC252025DFD37C952F21916FF2C5AA2460CD97CBD7D9653E8CDBCD340C29F6F86991914FB5F029289F2826AF33EAD9EB823AF0DF70FDD19FC4AE941E3CFA7F020000FFFFDE9A70EE93140000);
DELETE FROM [EdmMetadata];
INSERT INTO [EdmMetadata] ([ModelHash]) VALUES ('7A1D3FB94B39A8198EF177EDE6FF734EE97083E664B613C98EA9F74BA468B42F');
COMMIT TRANSACTION;

 

 

Con esto hemos acabado esta primera mini-serie sobre las migraciones. Esperemos que se siga trabajando en completar nuevas features y seguir escuchando todo el feedback que la comunidad está aportando.

 

Saludos

Unai

EF vNext-Migrations – I

Hace relativamente poco tiempo que salió a la luz, la primera CTP de lo que se conoce como EF Migrations, creo en el mes de agosto, y, justamente ahora, se ha publicado la segunda de las alpha de esta feature que tendremos disponible en la siguiente actualización del producto.  Aunque  en realidad, el concepto de “migraciones” no es nada nuevo, de hecho, es algo bastante común en nuestros desarrollos, sobre todo si la frecuencia de cambio es alta, existen algunas de herramientas que nos permiten hacer estos trabajos de una forma más ligera, como por ejemplo  Fluent Migrator (podéis ver un pequeño getting started), o Migrator .NET o MigSharp. Desde el equipo de EF se dieron cuenta de que esto es una parte fundamental del trabajo de los desarrolladores y, están creando out-of-box lo necesario para que dispongamos de esta funcionalidad. Junto con la información sobre esta nueva alpha también han publicado un pequeño walkthroug sobre como trabajar con las migraciones. Yo por mi parte, como no me gusta repetir lo que otros escriben, haré el mio, intentando contar también mis impresiones sobre el teme. Para este pequeño ejemplo partiremos de un pequeño insignificante modelo y su correspondiente unidad de trabajo tal y como lo vemos a continuación.

 

NOTA: Antes de empezar conviene recordar que EntityFramework.Migrations solamente funciona si se dispone de una base de datos SQLEXPRESS o en su defecto un alias apuntando a este nombre de instancia.

    public class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    class CRMUnitOfWork
        :DbContext
    {
        public IDbSet<Customer> Customers { get; set; }
    }

A mayores, hemos puesto en la configuración de nuestra aplicación la ruta con la base de datos con la que trabajamos, suele ser la opción más realista, aunque si queréis saltar este paso podéis dejar que el sistema de convenciones trabaje por vosotros.

 

<?xml version=1.0 encoding=utf-8 ?>

<configuration>

  <connectionStrings>

    <add name=DBMigrations.CRMUnitOfWork

         connectionString=Server=.;Initial Catalog=CRMUnitOfWork;Integrated Security=true;MultipleActiveResultSets=true

         providerName=System.Data.SqlClient/>

  </connectionStrings>

</configuration>

 

La idea inherente a las “migraciones”, es, disponer de un sistema que nos permita ir modificando una base de datos existente, ante cambios de nuestro modelo, de tal forma que, incluso pudieramos movernos entre distintas versiones de ella en la misma forma en la que nos movemos en versiones de modelos diferentes. Iremos viendo funcionalidades según vayamos avanzando con el post. Lo primero de todo será incluir el paquete de NuGet que nos permite trabajar con las Migraciones, este paquete se llama EntityFramework.Migrations.

 

Nota: El primer paquete que sacaron de esta Alpha 2 contenía un error en la cadena de dependencias ( no estaba incluida la dependencia con Sql Server Compact) y daba un error, aseguraros que la versión con la que trabajais es EntityFramework.Migrations 0.6.1.0.

Una vez instalado el paquete de migraciones en nuestro proyecto se incluirá una nueva carpeta llamada Migrations y dentro de ella se situará un archivo de configuración llamado Settings, cuyo contenido se puede ver a continuación:

    public class Settings : DbMigrationContext< /* TODO: put your code first context type name here */ >
    {
        public Settings()
        {
            AutomaticMigrationsEnabled = false;
            SetCodeGenerator<CSharpMigrationCodeGenerator>();
            AddSqlGenerator<SqlConnection, SqlServerMigrationSqlGenerator>();

            // Uncomment the following line if you are using SQL Server Compact 
            // SQL Server Compact is available as the SqlServerCompact NuGet package
            // AddSqlGenerator<System.Data.SqlServerCe.SqlCeConnection, SqlCeMigrationSqlGenerator>();
        }
    }

 

La idea principal de esta clase es la de configurar ciertos elementos de nuestro sistema de migraciones, en concreto podemos ver si tenemos o no las migraciones aUntitledutomaticas activadas, sobre lo que hablaremos más adelante, el lenguaje a utilizar en la generación de código, por ahora solamente está soportado C#, y el tipo de proveedor con el que trabajaremos ( Sql Server o Sql Compact son los únicos disponibles por ahora). Como puede observar, la clase nos pide indicar el contexto a utilizar en su parámetro genérico, en nuestro caso estableceremos CRMUnitOfWork.

El primer paso está dado, ahora, empezarmos por crear nuestra primera migración, que consistirá en establecer la primera estructura de nuestra base de datos para el modelo de entidades que tenemos. Para ello, en la propia consola de “NuGet Package Manager” podemos ejecutar el comando “Add-Migration FirstSteep”, dónde FirstSteep es el nombre que le queramos dar a la migración.

 

 

Una vez ejecutado el comando, este nuevo paquete nos genera un elemento conocido como una DbMigration  y, puesto que es la migración inicial esta consta de la esetructura para crear la base de datos con la que pretende trabajar el modelo. A continuación se puede ver el código de esta nueva clase incorporada al proyecto.

 

    public partial class MyFirstMigration : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "Customers",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        FirstName = c.String(),
                        LastName = c.String(),
                    })
                .PrimaryKey(t => t.Id);
            
            CreateTable(
                "EdmMetadata",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        ModelHash = c.String(),
                    })
                .PrimaryKey(t => t.Id);
            
        }
        
        public override void Down()
        {
            // This preview of Code First Migrations does not support downgrade functionality.
        }
    }

Untitled

Con estos pasos, en realidad aún no hemos creado la base de datos, para realizarlo, ejecutaremos otro comando llamando Update-Database, el cual, nos ejecutará la migración en la base de datos que indique la unidad de trabajo( se podría utilizar el flag –script para generar un fichero .sql en su defecto). La ejecución de este comando, además de la creación de la estructura que implica el modelo crea una tabla de sistema denominada __MigrationHistory la cual contiene la información de las distintas migraciones ejecutadas sobre esta base de datos y los hash de los diferentes modelos con los que se ha trabajado. Aunque por ahora esta feature no está soportada, en un futuro no muy lejano podremos movernos de “adelante hacia atrás” en las distintas migraciones que hagamos de nuestros modelos.

 

Bien, supongamos ahora, que modificamos la entidad Customer de nuestro modelo y agregamos a la misma una propiedad llamada Email. Este cambio implicaria también un cambio en nuestra base de datos, hay una nueva columna que agregar a la estructura de la tabla correspondiente.  Gracias a Migrations, podremos hacer esto de una forma simple, basta con volver a ejecutar otra vez el comando Add-Migration con el correspondiente nombre que le queramos dar a la migración, en nuestro caso AddEmailProperty, y actualizar la base de datos con Update-Database.

 

 

    public partial class AddEmailProperty : DbMigration
    {
        public override void Up()
        {
            AddColumn("Customers", "Email", c => c.String());
        }
        
        public override void Down()
        {
            // This preview of Code First Migrations does not support downgrade functionality.
        }
    }
 

Bien, hasta aquí ya hemos visto algunas de las posibilidades, pero en realidad hay muchas más. El scaffolding que se genera cuando hacemos Add-Migration podemos tocarlo para agregar algunos elementos que no solamente estén relacionados con la estructura de una tabla sino que también podemos por ejemplo agregar algún índice ( cosa que no podemos hacer con el API de mapeo de code first por ejemplo). Así, si nos interesara por ejemplo que Email tuviera un índice unique podríamos modificar la migración anterior y agregar algo como lo siguiente:

 

CreateIndex("Customers", new string[] { "Email" }, unique: true);
 

Espero que esto os resultará intersante, en la siguiente entrada seguiremos con este tema, viendo como funcionan las migraciones automáticas y sobre todo los siguientes pasos que tomarán en el equipo de producto de EF con respecto a este tema.

 

Saludos

Unai

[IASA] : Eric Evans y Udi Dahan en Madrid, apúntate, disfrútalo…

¡Eric Evans y Udi Dahan en Madrid!

Nueva creación de IASA-Spain Chapter y Conferencia DDD (Domain Driven Design) con Eric Evans y Udi Dahan, como evento inaugural de IASA-Spain Chapter.

IASA-Spain Chapter ha sido recientemente creado como una iniciativa genérica de Arquitectos de TI, en España.
IASA-Spain Chapter se complace en invitarle a los siguientes eventos y actividades de formación, en este caso todos ellos relacionados con DDD (Domain Driven Design):

1.- Conferencia DDD IASA-Spain – ‘Arquitectura y Diseño de aplicaciones empresariales’ – 7 Nov. 2011 (registro gratuito), en la Facultad de Informática de la Universidad Politécnica de Madrid, con keynotes de Eric Evans (Introducción a DDD y aplicaciones empresariales complejas) y Udi Dahan (Introducción a CQRS y aplicaciones altamente escalables). También dispondremos de sesiones prácticas relacionando DDD, patrones de arquitectura y diseño, con plataformas JAVA y .NET, así como un tiempo de debate abierto.
Regístrese aquí. (Registro gratuito):
http://dddiasaconference.eventbrite.com/

2.- Workshop DDD – 8 Nov. 2011 (Jornada completa con Eric Evans sobre Domain Driven Design), 1ª impartición.
Regístrese aquí. (Coste por registro):
http://dddworkshopee.eventbrite.com/

3.- Workshop CQRS (Command and Query Responsability Segregation) – 8 Nov. 2011 (Jornada completa con Udi Dahan sobre CQRS y aplicaciones altamente escalables).
Regístrese aquí. (Coste por registro):
http://cqrsworkshopud.eventbrite.com/

4.- Workshop DDD – 10 Nov. 2011 (Jornada completa con Eric Evans), 2ª impartición (Repetición mismo contenido que el workshop DDD del día 8).
Regístrese aquí. (Coste por registro):
http://dddworkshopee2.eventbrite.com/

Info global en:
http://www.iasaglobal.org/assnfe/ev.asp?ID=118&SnID=1571614239/

IASA:
http://www.iasaglobal.org