Entity Framework – Code First Migrations com Mysql
Olá a todos.
Hoje estarei demonstrando como utilizar Migrations com o banco MySQL. Existem diversos tutoriais na internet que ensinam com o SQL Server, então como eu tive uma certa dificuldade de utilizar com outro banco estarei demonstrando o processo.
Estou levando em conta que você já tem um conhecimento básico do Entity Framework, por isso não entrarei em muitos detalhes sobre o que é e o que faz um contexto por exemplo..
Neste tutorial estou utilizando o Visual Studio 2012 Express que acompanha o Entity Framework 5 e .NET Framework 4.5. Será necessário que você possua um instância ativa do banco de dados MySQL.
Primeiro, faça o download e instale o driver MySQL Connectors disponível em:http://dev.mysql.com/downloads/connector/net/.
#Afinal, o que é migrations?
O Migrations ajuda você a realizar o controle de versão das alterações feitas em seu banco de dados e das propriedades dos modelos da sua aplicação. O suporte a Migrations pelo Entity foi implementado na versão 4.3.1 um do framework.
O conceito de Migrations não é novo e nem único do Entity Framework, o ActiveRecord, ORM do framework Rails para Ruby, já possui há um bom tempo o Migrations e esse é um dos pontos fortes dessa abordagem, focar o programador apenas na linguagem da aplicação, evitando que ele tenha que escrever SQL’s, tornando o desenvolvimento muito mais ágil.
O Code First Migrations permite a você criar tabelas, realizar alterações, voltar versões e controlar todas as migrações. Imagine a praticidade?
#Show me the code!
Abra o Visual Studio e crie um Console Application: ExemploMigrations.
Importe a referência do Entity e do drive do MySQL(a dll estará onde você instalou o conector):
Agora vamos criar a classe Pessoa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
namespace ExemploMigrations
{
[Table( "dbo.pessoas" )]
class Pessoa
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Nome { get; set; }
public string Telefone { get; set; }
public string Email { get; set; }
public string Cpf { get; set; }
}
} |
Agora vamos começar a configurar o Entity para utilizar o MySQL. Utilize um banco de teste ou crie algum, o meu se chamará banco_migrations.
No Visual Studio crie um arquivo Application Configure File:
O conteúdo do arquivo deve ser:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <? xml version = "1.0" encoding = "utf-8" ?>
< configuration >
< configSections >
< section name = "entityFramework" type = "System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission = "false" />
</ configSections >
< connectionStrings >
< add name = "Contexto" connectionString = "Database=banco_teste;Data Source=localhost;User Id=root;Password=Teste" providerName = "MySql.Data.MySqlClient" />
</ connectionStrings >
< entityFramework >
< defaultConnectionFactory type = "System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework" >
< parameters >
< parameter value = "v11.0" />
</ parameters >
</ defaultConnectionFactory >
</ entityFramework >
</ configuration > |
A tag connectionStrings possui os parâmetros necessários para comunicação com o banco.
Agora criaremos a nossa classe de Contexto que intermediará as ações da aplicação com o banco de dados:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
using System.Text;
namespace ExemploMigrations
{
class Contexto:DbContext
{
public DbSet Pessoas { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove();
modelBuilder.Conventions.Remove();
}
}
} |
Na classe Program, no método Main iremos realizar um insert de uma pessoa:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ExemploMigrations
{
class Program
{
static void Main(string[] args)
{
Contexto contexto = new Contexto();
contexto.Pessoas.Add( new Pessoa { Nome = "Guilherme" , Cpf = "12345678909" , Email = "guihgf@gmail.com" , Telefone (11)11111111" });
contexto.SaveChanges();
}
}
} |
#Code First Migrations
Agora sim utilizaremos o Migrations, lembrando que não criamos e nem vamos criar a tabela de pessoas, vamos deixar isso a cuidados do Code First Migrations.
Vamos habilitar o Package Manager Console:
No console, instalaremos o package do entity com o comando: Install-Package EntityFramework.
Em seguida habilitaremos o uso do Migration: Enable-Migrations.
PM> Enable-Migrations
Checking if the context targets an existing database…
Code First Migrations enabled for project ExemploMigrations.
Agora sim criaremos a nossa primeira migration com Add-Migration Pessoas:
PM> Add-Migration Pessoas
Scaffolding migration ‘Pessoas’.
The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running ‘Add-Migration 201306170227241_Pessoas’ again.
Como descrito acima foi criado o arquivo 201306170227241_Pessoas.cs:
A Migration possui dois métodos, Up e Down. O up possui todo o código da alteração proposta pela Migration, no caso a tabela Pessoas e seus campos, já o Down seria o Rollback da alteração, que no caso é a exclusão da tabela Pessoas, você também pode reescrever estes dois métodos.
Agora a alteração chave, se pedirmos para o entity criar a tabela no banco ele usará a linguagem T-SQL que é a linguagem nativa no SQL Server, isso seria um problema, pois estamos utilizando MySql. Para isso alteraremos o construtor da classe Configuration.cs para que o gerador de Sql utilize o MySql:
1 2 3 4 5 | public Configuration()
{
AutomaticMigrationsEnabled = false ;
SetSqlGenerator( "MySql.Data.MySqlClient" , new MySql.Data.Entity.MySqlMigrationSqlGenerator());
} |
Agora poderemos atualizar a base de dados com o comando: Update-database -Verbose.
E bamm!! É lançada uma exceção:
Specify the ‘-Verbose’ flag to view the SQL statements being applied to the target database.
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.IO.FileLoadException: Could not load file or assembly ‘EntityFramework, Version=4.3.1.0,
Estou utilizando a versão 5.0 do Entity Framework e até o momento o driver de conexão do MySql suporta a 4.3.1.0. Para resolver este problema precisamos utilizar a versão informada pelo framework, para isso utilize o comando: Uninstall-Package EntityFramework para desinstalar a versão atual e Install-Package EntityFramework -Version 4.3.1 para instalar a versão necessária.
Agora poderemos atualizar a base de dados com o comando: Update-database -Verbose
Update-database -Verbose
Using NuGet project ‘ExemploMigrations’.
Using StartUp project ‘ExemploMigrations’.
Target database is: ‘banco_teste’ (DataSource: 127.0.0.1, Provider: MySql.Data.MySqlClient, Origin: Configuration).
Applying explicit migrations: [201306170227241_Pessoas].
Applying explicit migration: 201306170227241_Pessoas.
create table `dbo.pessoas` (`Id` int not null auto_increment primary key ,`Nome` longtext,`Telefone` longtext,`Email` longtext,`Cpf` longtext) engine=InnoDb auto_increment=0
create table `__MigrationHistory` (`MigrationId` varchar(255) not null ,`CreatedOn` datetime not null ,`Model` longblob not null ,`ProductVersion` varchar(32) not null ,primary key ( `MigrationId`) ) engine=InnoDb auto_increment=0
insert into `__MigrationHistory` (`migrationId`, `createdOn`, `model`, `productVersion`) values ( ’201306170227241_Pessoas’, ’2013-06-17 02:29:45
E pronto, executamos a nossa primeira migração http://s0.wp.com/wp-includes/images/smilies/icon_biggrin.gif?m=1129645325g
Olhando o banco_teste, podemos verificar que foram criadas a nossa tabela pessoas e uma outra denominada __migrationhistory, responsável por realizar o versionamento de nossas mgrações.
Agora vamos executar o nosso projeto, para que seja inserida uma Pessoa e pronto nosso código esta funcional:
Certo, agora criaremos uma segunda versão, onde será adicionada a idade da pessoa, para isso basta criar a propriedade Idade na classe Pessoa:
1 2 3 4 5 6 7 8 9 10 11 | [Table( "dbo.pessoas" )]
class Pessoa
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Nome { get; set; }
public string Telefone { get; set; }
public string Email { get; set; }
public string Cpf { get; set; }
public int Idade { get; set; }
} |
Em seguida criaremos uma nova migração:
Add-Migration Pessoas_add_idade
Scaffolding migration ‘Pessoas_add_idade’.
The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running ‘Add-Migration 201306170233081_Pessoas_add_idade’ again.
Repare que o método UP adiciona a coluna idade na tabela pessoas. Agora vamos executar a migração:
PM> Update-database -Verbose
Using NuGet project ‘ExemploMigrations’.
Using StartUp project ‘ExemploMigrations’.
Target database is: ‘banco_teste’ (DataSource: 127.0.0.1, Provider: MySql.Data.MySqlClient, Origin: Configuration).
Applying explicit migrations: [201306170233081_Pessoas_add_idade].
Applying explicit migration: 201306170233081_Pessoas_add_idade.
alter table `dbo.pessoas` add column `Idade` int not null
insert into `__MigrationHistory` (`migrationId`, `createdOn`, `model`, `productVersion`) values ( ’201306170233081_Pessoas_add_idade’, ’2013-06-17 02:34:16′
Pronto, coluna idade criada, visualize o client do MySql e a coluna foi inserida com sucesso, agora vamos supor que tivemos algum problema na implantação dessa versão e precisamos voltar para a versão anterior. Isso seria um problema, mas o Entity nos ajuda, basta executar o update novamente, mas setando a versão anterior:
PM> Update-Database -TargetMigration:201306170240268_Pessoas
Specify the ‘-Verbose’ flag to view the SQL statements being applied to the target database.
Reverting migrations: [201306170241051_Pessoas_add_idade].
Reverting explicit migration: 201306170241051_Pessoas_add_idade.
Assim foi executado o comando Down da versão 201306170241051_Pessoas_add_idade que é remover a coluna idade da tabela pessoas.
#Migrações Automáticas
Não recomendo, mas é possível que o Entity gerencie as suas migrações automaticamente a cada update que você realizar, o problema é que não criados updates e downgrades, pois não intermediamos os pontos de migração (cada versão). Para habilitar a migração automática, altere AutomaticMigrationsEnabled para true na classe Configuration.cs.
#Código
Código deste projeto está disponível em: http://github.com/guihgf/migrations_entity
Texto escrito originalmente em: http://guilhermefermino.net/2013/06/18/entity-framework-code-first-migrations-com-mysql/