Running & Scripting Migrations From Code

05/09/2012 23:16:00 By Felipe Pessoto

Rowan Miller explained how to script Migrations from code, but his code was write using a pre-RTM version of Code First Migrations and doesn´t work when using EntityFramework 4.3.1.

I did some reflector work and get a solution that should work.

The most obvious difference is that some classes was renamed. Another point, at least in my case I needed to configure some additional things, like MigrationsAssembly
and MigrationsNamespace, these properties are used to find Code-Based migrations, that is what I want instead of use Automatic Migrations.

The code that does the magic:

System.Data.Entity.Migrations.DbMigrationsConfiguration configuration =newSystem.Data.Entity.Migrations.DbMigrationsConfiguration();
configuration.ContextType=typeof(FujiyBlogDatabase);//TODO Change to your DbContext
configuration.MigrationsAssembly= configuration.ContextType.Assembly;
configuration.MigrationsNamespace="FujiyBlog.Core.Migrations";//TODO Namespace that contains your migrations classes

var migrator =new System.Data.Entity.Migrations.DbMigrator(configuration);

if(true)//TODO Do you want the script or Update de database?
{
    var scriptor =newSystem.Data.Entity.Migrations.Infrastructure.MigratorScriptingDecorator(migrator);
    string script = scriptor.ScriptUpdate(sourceMigration:null, targetMigration:null);
}
else
{
    migrator.Update();
}

Script para gerar Insert no SQL Server

04/06/2012 21:38:41 By Felipe Pessoto

Tem uma procedure do Vyas que sempre me salva, pra gerar o script de INSERT´s de uma tabela, vou compartilhar aqui no blog uma versão alterada para executar direto sem criar a procedure, que acho que é mais prático. Também tem um modo debug que printa o SELECT que é feito pra gerar o INSERT assim você pode usar o SELECT pra criar uma aplicação que faça cargas, usei recentemente pra uma aplicação que copiava alguns dados do SQL Server pro SQLite(precisou de alguma adaptações no script pro SQLite).

GerarInserts.txt

RavenDB - Introdução

02/28/2012 23:30:00 By Felipe Pessoto

Nos últimos anos tem se falado muito sobre NoSQL, sobre os ganhos em performance, escalabilidade, simplicidade, etc. Ele não veio para substituir os bancos relacionais, mas é mais uma alternativa a se considerar. Na verdade usamos bancos relacionais como bala de prata, simplesmente porque eles estão lá, é praticamente uma regra, mas nem sempre são a melhor opção. Como disse Abraham Maslow, "Para quem só sabe usar martelo, todo problema é um prego."

O RavenDB é especial para desenvolvedores .NET pois é feito em .NET e Open Source. O que não quer dizer que ele é de graça, caso você queira usar em algum produto comercial você precisa comprar uma licença, mas não se preocupe pois é muito barata em comparação aos bancos relacionais e o ganho em produtividade paga o custo rapidamente.

Além disso, como é destacado no logo, ele é um banco de dados orientado a documentos de 2ª geração. Entre suas vantagens podemos destacar:

  • ACID
  • Sem Locking
  • Seguro
  • API amigável
  • LINQ
  • Compatível com DDD(Aggregates)
  • Multi-Level cache
  • Escalável
  • Schema Free
  • Sharding
  • Replication
  • Full Text Seach (contruido com Lucene)
  • Entre muitos outros...

Neste post introdutório quero apenas mostrar (enquanto aprendo) como fazer um projeto bem simples, apenas gravando e lendo um documento no banco.

Criei um website vazio pra usar como teste e pelo NuGet você pode instalar o RavenDB-Embedded, que roda junto com o site em vez de instalar um serviço.

O primeiro passo é criar uma instância Singleton do DocumentStore, isso pode ser feto facilmente com uma variavel static readonly, ou como no meu caso eu uso o Global.asax, no Application_Start crio uma instancia que é usada até o site ser reciclado ou parado:

    private static IDocumentStore DocumentStore { get; set; }
    void Application_Start(object sender, EventArgs e)
    {
        DocumentStore = new EmbeddableDocumentStore
        {
            DataDirectory = "Data",
            UseEmbeddedHttpServer = true
        }.Initialize();
    }

O DocumentStore será usado pra criar um IDocumentSession quando acessarmos o banco de dados. O IDocumentSession representa um Unit Of Work. Para facilitar criamos uma Sessão no inicio de cada Request no Global.asax e colocamos no dicionário Items do Request. A melhor forma de fazer isso depende da sua aplicação, você poderia usar um IoC, ou criar a Sessão toda vez que quiser usar o banco, é mais ou menos como fazemos com o DbContext ou ObjectContext do Entity Framework.

    void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpContext.Current.Items["CurrentRequestRavenSession"] = DocumentStore.OpenSession();
    }

A API básica é bastante simples e é algo que o Ayende valoriza muito, para ter uma idéia são apenas 6 métodos.
Para gravar um novo objeto não poderia ser mais simples, apenas duas linhas:

Livro novoLivro = new Livro
                        {
                            Nome = TxtNome.Text,
                            Preco = decimal.Parse(TxtPreco.Text),
                            Autores = TxtAutores.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
                        };
RavenSession.Store(novoLivro);
RavenSession.SaveChanges();

Com a mesma facilidade podemos fazer as outras operações, como consultar um documento pelo Id:

Livro livroEditado = RavenSession.Load<Livro>("livros/" + HidId.Value);

Atualizar:

Livro livroEditado = RavenSession.Load<Livro>("livros/" + HidId.Value);
livroEditado.Nome = TxtNome.Text;
livroEditado.Preco = decimal.Parse(TxtPreco.Text);
livroEditado.Autores = TxtAutores.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
RavenSession.SaveChanges();

Apagar um documento:

Livro livroApagado = RavenSession.Load<Livro>("livros/" + id);
RavenSession.Delete(livroApagado);
RavenSession.SaveChanges();c

E uma Query simples:

GrvTodos.DataSource = RavenSession.Query<Livro>();

Isso é o básico, o RavenDB tem muitos recursos avançados que pretendo falar nos próximos posts, a medida que vou me familiarizando com este excelente Document DB.

Caso queira testar, estou disponibilizando o código que usei. Para se ter uma idéia, a maior parte do código é pra controlar os Controles do Form do que o banco de dados em si.

RavenDbIntroducao.zip

Sugestão que enviei pro Entity Framework foi aceita

02/02/2012 08:18:13 By Felipe Pessoto

A Microsoft abriu uma série de forums no UserVoice para receber novas idéias sobre seus produtos, como Entity Framework, ASP.NET, WCF, etc. Os developers podem enviar novas idéias e votar, cada um tem direito à 10 votos.

Enviei uma sugestão pedindo que os Assemblies do Entity Framework sejam independentes do .NET Framework. Nos blogs os developers do EF já tinham comentado que vão tentar remover cada vez mais o Core do EF de dentro do .NET e agora vi a confirmação no UserVoice que minha sugestão está sobre revisão.

Segundo os ultimos posts no blog ADO.NET, no .NET 4.5 já poderemos ver uma evolução nesse sentido, mas como o 4.5 é uma atualização in-place, eles não tem tanta liberdade, nem podem remover classes.

Atualização: O Diego Vega acabou de passar a sugestão de "Under Review" pra "Planned"

Organizando planos de execução gigantes

07/25/2011 08:16:00 By Felipe Pessoto

Neste post quero mostrar uma forma de organizar um plano de execução gigante.

Muitas vezes quando trabalhamos com bancos de dados antigos e complexos, acabamos lidando com problemas de performance e o plano de execução da algumas dicas por onde começar o trabalho de otimização.

O problema é quando o próprio plano de execução é grande e complexo, dificultando a leitura e tornando o simples trabalho de achar os pontos críticos em uma tarefa entediante.

O primeiro passo pra isso é salvar o plano de execução em XML. No Sql Management Studio, basta clicar com o botão direito sobre o Plano de Execução e selecionar "Save Execution Plan As". Após isso é necessário abrir o plano de execução no bloco de notas e re-salvar em Unicode, pois o XML está marcado como Unicode, mas o Management Studio salva em condificação ANSI, o que gera um problema no próximo passo.

Assim que temos o arquivo XML preparado, basta fazer alguns SELECT´s no arquivo XML, onde podemos ordenar por tempo estimado de CPU, IO ou a diferença entre o número de linhas esperados e o número atual:

DECLARE @xml XML

SELECT @xml =(SELECT * FROM OPENROWSET (BULK 'C:\Users\Usuario\Desktop\Exec.txt', SINGLE_BLOB) XMLShowPlan)

SELECT  RelOp.op.value('@NodeId', 'int') AS NodeId,
        RelOp.op.value('@PhysicalOp', 'NVARCHAR(75)') AS Operation,
        RelOp.op.value('@EstimateCPU', 'float') AS EstimatedCPU,
        RelOp.op.value('@EstimateIO', 'float') AS EstimatedIO
FROM    @xml.nodes('declare default element namespace
    "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
    //RelOp') AS RelOp ( op )
ORDER BY [EstimatedCPU] DESC

SELECT  RelOp.op.value('@NodeId', 'int') AS NodeId,
        RelOp.op.value('@PhysicalOp', 'NVARCHAR(75)') AS Operation,
        RelOp.op.value('@EstimateCPU', 'float') AS EstimatedCPU,
        RelOp.op.value('@EstimateIO', 'float') AS EstimatedIO
FROM    @xml.nodes('declare default element namespace
    "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
    //RelOp') AS RelOp ( op )
ORDER BY [EstimatedIO] DESC;

WITH ExPlan AS(

SELECT  RelOp.op.value('@NodeId', 'int') AS NodeId,
        RelOp.op.value('@PhysicalOp', 'NVARCHAR(75)') AS Operation,
        RelOp.op.value('@EstimateCPU', 'float') AS EstimatedCPU,
        RelOp.op.value('@EstimateIO', 'float') AS EstimatedIO,
        RelOp.op.value('@EstimateRows','float') AS EstimatedRows,
        RelOp.op.value('(./*:RunTimeInformation/*:RunTimeCountersPerThread)[1]/@ActualRows','int') AS ActualRows
FROM    @xml.nodes('declare default element namespace
    "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
    //RelOp') AS RelOp ( op )
)

SELECT e.NodeId
 ,e.Operation
 ,e.EstimatedRows
 ,e.ActualRows
 ,(e.EstimatedRows/ActualRows) AS EstActualRatio
  FROM [ExPlan] e
  WHERE e.EstimatedRows > 0
  and e.ActualRows > 0
ORDER BY [EstActualRatio] ASC

Você pode criar outros selects para diversos casos, mas com isso já temos uma base.