<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>tucaz.blog.now() &#187; Banco de Dados</title>
	<atom:link href="http://blog.tucaz.net/category/desenvolvimento/banco-de-dados/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.tucaz.net</link>
	<description>Software architecture, agile and all that stuff that you can find everywhere</description>
	<lastBuildDate>Tue, 11 Jan 2011 21:00:29 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Performance: NHibernate versus ADO.NET</title>
		<link>http://blog.tucaz.net/2010/08/31/performance-nhibernate-versus-ado-net/</link>
		<comments>http://blog.tucaz.net/2010/08/31/performance-nhibernate-versus-ado-net/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 01:18:21 +0000</pubDate>
		<dc:creator>tucaz</dc:creator>
				<category><![CDATA[Banco de Dados]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[NHibernate]]></category>
		<category><![CDATA[adhoc]]></category>
		<category><![CDATA[ADO.NET]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[stored procedures]]></category>

		<guid isPermaLink="false">http://blog.tucaz.net/?p=466</guid>
		<description><![CDATA[Disclaimer
Os testes neste post apresentados não representam uma amostra exata ou fidedigna que represente uma condição real de acesso a dados de uma aplicação a fim de comparar a performance das duas tecnologias. A idéia é apenas mostrar alguns dados e exemplos com o objetivo de dismistificar a idéia de que ORM é uma ferramenta [...]]]></description>
			<content:encoded><![CDATA[<h1><em><span style="color: #ff0000">Disclaimer</span></em></h1>
<p><em><span style="color: #ff0000">Os testes neste post apresentados não representam uma amostra exata ou fidedigna que represente uma condição real de acesso a dados de uma aplicação a fim de comparar a performance das duas tecnologias. A idéia é apenas mostrar alguns dados e exemplos com o objetivo de dismistificar a idéia de que ORM é uma ferramenta lenta e estes testes são apenas um exercício.</span></em></p>
<p><em><span style="color: #ff0000">Sou usuário de NHibernate e defendo o uso de ORM’s portanto as conclusões apresentadas com certeza não são as mais imparciais possíveis.</span></em></p>
<p>Motivado <a title="DDD - Objetos de consulta usando ORM - o que vcs acham? @ DotNetArchitects" href="http://groups.google.com/group/dotnetarchitects/browse_thread/thread/dc01630511ec34ec">por esta thread no DNA hoje</a> decidi fazer alguns testes de perfomance pra comparar acesso a dados utilizando ADO.NET nativo (queries AdHoc e Stored Procedures) versus NHibernate.</p>
<p>Sempre rolam diversas discussões a respeito do assunto e a conclusão que geralmente se chega é de que qualquer ORM vai ser mais lento do que uma chamada nativa. É uma conclusão óbvia já que utilizar um ORM é adicionar uma camada de abstração a mais dentro da nossa aplicação. No entanto, até então eu nunca havia efetuado nenhuma medição pra ver qual a diferença de performance.</p>
<p>Todos os testes foram executados na minha máquina com código compilado em modo Release com banco de dados Sql Server 2008 também local.</p>
<p>Vamos aos testes.</p>
<h1>Cenário de testes</h1>
<p>Criei uma tabela (Product) e populei com cerca de 500 registros vindos do AdventureWorks (banco de dados exemplo do SqlServer).</p>
<p><a href="http://blog.tucaz.net/wp-content/uploads/2010/08/image.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Modelo de Dados" border="0" alt="Modelo de Dados" src="http://blog.tucaz.net/wp-content/uploads/2010/08/image_thumb.png" width="237" height="175" /></a></p>
<p>Contra essa tabela executei duas categorias de testes:</p>
<ol>
<li>Carregar todos os registros da tabela em um List&lt;&gt; </li>
<li>Carregar apenas um registro </li>
</ol>
<p>Pra ficar mais interessante fiz algumas variações dos testes:</p>
<ul>
<li>Query AdHoc/Inline </li>
<li>Query AdHoc/Inline com hidratação<strong>[1]</strong> via reflection </li>
<li>Query utilizando uma procedure </li>
<li>NHibernate com LINQ </li>
<li>NHibernate com HQL </li>
<li>NHibernate com Criteria </li>
<li>Nhibernate com Projections </li>
</ul>
<p>Como rodando uma única vez não foi possível obter dados suficientes, executei cada teste dentro de um loop com 1000 (numberOfIterations = 1000) iterações que resultou no código abaixo:</p>
<p>Método principal:</p>
<pre class="csharp" name="code">static void Main(string[] args)
{
    for (int i = 1; i &lt;= 3; i++)
    {
        Console.WriteLine(&quot;Test &quot; + i.ToString());
        Console.WriteLine(&quot;======================&quot;);

        SqlAdHocAllProducts();
        SqlAdHocAllProductsWithReflection();
        SProcAllProducts();
        NHibernateAllProductsWithLinq();
        NHibernateAllProductsWithHql();
        NHibernateAllProductsWithCriteria();
        NHibernateAllProductsWithProjections();

        SqlAdHocOneProduct();
        SqlAdHocOneProductWithReflection();
        SProcOneProduct();
        NHibernateOneProduct();

        Console.WriteLine();
    }

    Console.ReadLine();
}</pre>
<p>
  <br />Um dos métodos usando Sql AdHoc e outro usando NHibernate:</p>
<p></p>
<pre class="csharp" name="code">private static void SqlAdHocAllProducts()
{
    List&lt;Product&gt; allProducts = null;

    var connectionString = &quot;Data Source=(local);Integrated Security=SSPI;Database=TDC2010;&quot;;
    var select = @&quot;SELECT P.Id, P.Description, P.Name, P.Price FROM dbo.Product P&quot;;

    var connection = new SqlConnection(connectionString);
    connection.Open();

    Stopwatch watch = new Stopwatch();
    watch.Start();

    for (int i = 0; i &lt; numberOfIterations; i++)
    {
        allProducts = new List&lt;Product&gt;();
        var command = new SqlCommand(select, connection);
        var reader = command.ExecuteReader();

        while (reader.Read())
        {
            allProducts.Add(new Product()
                {

                    Id = Convert.ToInt32(reader[&quot;Id&quot;]),
                    Name = Convert.ToString(reader[&quot;Name&quot;]),
                    Description = Convert.ToString(reader[&quot;Description&quot;]),
                    Price = Convert.ToDecimal(reader[&quot;price&quot;])
                });
        }

        reader.Close();
    }

    watch.Stop();

    connection.Close();
    connection.Dispose();

    Console.WriteLine(
        &quot;Loading &quot; + allProducts.Count + &quot; Products with Sql AdHoc took &quot; + watch.ElapsedMilliseconds + &quot; ms&quot;);
}</pre>
<p>
  </p>
<pre class="csharp" name="code">private static void NHibernateAllProductsWithLinq()
{
    List&lt;Product&gt; allProducts = null;

    var session = CreateForSqlServer().OpenSession();

    Stopwatch watch = new Stopwatch();
    watch.Start();

    for (int i = 0; i &lt; numberOfIterations; i++)
    {
        allProducts = session.Linq&lt;Product&gt;().ToList();
    }

    watch.Stop();

    session.Close();

    Console.WriteLine(
        &quot;Loading &quot; + allProducts.Count + &quot; Products with NHibernate took &quot; + watch.ElapsedMilliseconds + &quot; ms&quot;);
}</pre>
<p><strong>Vou omitir o restante dos métodos para evitar duplicações já que eles são apenas variações dos dois exemplos acima.</strong></p>
<h1>Resultado Geral</h1>
<p><a href="http://blog.tucaz.net/wp-content/uploads/2010/08/image1.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Resultados dos Testes" border="0" alt="Resultados dos Testes" src="http://blog.tucaz.net/wp-content/uploads/2010/08/image_thumb1.png" width="681" height="648" /></a></p>
<h1>Análise dos Resultados</h1>
<h3>Stored Procedures versus Queries AdHoc/Inline [500 registros]</h3>
<p>A diferença entre o uso de stored procedures e queries AdHoc é praticamente inexistente. A diferença média medida foi de <strong>menos de 1%</strong>.</p>
<p>Isso acontece, pois não existe complexidade suficiente neste tipo de query para que a armazenagem do plano de execução no banco de dados faça diferença.</p>
<p>Portanto, na grande maioria dos cenários Stored Procedures não são necessárias.</p>
<h3>NHibernate versus NHibernate [500 registros]</h3>
<p>Na média, todas as variações de consulta utilizando NHibernate também tiveram <strong>mais ou menos o mesmo resultado (~1500ms)</strong> com exceção do uso de <strong>Projections</strong>, que levou o dobro<strong> (~3000ms)</strong> do tempo.</p>
<p>Não conheço o NHibernate suficiente pra afirmar com 100% de certeza o motivo, mas acredito que seja pelo fato de esse tipo de query retornar Arrays bidimensionais que são criados e redimensionados em runtime até que todos os itens possam ser acomodados.</p>
<h3>NHibernate versus ADO.NET [500 registros]</h3>
<p>Este e o comparativo mais importante. Carregando (e hidratando) 500 registros o ADO.NET é cerca de <strong>30% mais</strong> rapido do que o NHibernate. A causa dessa discrepância é uma só e se chama reflection.</p>
<p>Apesar de todas as otimizações o NHibernate utiliza-se de reflection para efetuar a hidratação<strong>[1] </strong>de todos os objetos e é dai que vem a queda de performance que fica clara quando executamos queries AdHoc usando hidratação via reflection conforme o código abaixo.</p>
<pre class="csharp" name="code">private static void SqlAdHocAllProductsWithReflection()
{
    List&lt;Product&gt; allProducts = null;

    var connectionString = &quot;Data Source=(local);Integrated Security=SSPI;Database=TDC2010;&quot;;
    var select = @&quot;SELECT P.Id, P.Description, P.Name, P.Price FROM dbo.Product P&quot;;

    var connection = new SqlConnection(connectionString);
    connection.Open();

    Stopwatch watch = new Stopwatch();
    watch.Start();

    for (int i = 0; i &lt; numberOfIterations; i++)
    {
        allProducts = new List&lt;Product&gt;();
        var command = new SqlCommand(select, connection);
        var reader = command.ExecuteReader();

        while (reader.Read())
        {
            var newProduct = Activator.CreateInstance&lt;Product&gt;();
            SetProperty(newProduct, &quot;Id&quot;, Convert.ToInt32(reader[&quot;Id&quot;]));
            SetProperty(newProduct, &quot;Description&quot;, Convert.ToString(reader[&quot;Description&quot;]));
            SetProperty(newProduct, &quot;Name&quot;, Convert.ToString(reader[&quot;Name&quot;]));
            SetProperty(newProduct, &quot;Price&quot;, Convert.ToDecimal(reader[&quot;Price&quot;]));
            allProducts.Add(newProduct);
        }

        reader.Close();
    }

    watch.Stop();

    connection.Close();
    connection.Dispose();

    Console.WriteLine(
&quot;Loading &quot; + allProducts.Count + &quot; Products with Sql AdHoc and Reflection took &quot; + watch.ElapsedMilliseconds + &quot; ms&quot;);
}

private static void SetProperty(object instance, string property, object val)
{
    Type t = instance.GetType();
    var prop = t.GetProperty(property, BindingFlags.Instance | BindingFlags.Public);
    prop.SetValue(instance, val, null);
}</pre>
<p>Este código quando executado demora cerca de <strong>6000ms, ou 4 vezes mais</strong>, do que o código executado pelo NHibernate.</p>
<p>Mas por que a diferença não é de 30%? Porque o NHibernate possui otimizações quanto ao modo de hidratar um objeto via reflection. No meu código acima podemos ver, por exemplo, que toda vez que chamo o método SetProperty o Type da propriedade a ser refletida ainda não está criado. Provavelmente o NHibernate deve manter cache deste tipo de informação (e de outras) a fim de otimizar o processo de hidratação das entidades.</p>
<h3>Stored Procedures versus Queries AdHoc/Inline [1 registro]</h3>
<p>Mesmo resultado do cenário onde 500 registros são carregados. Não há diferença.</p>
<h3>NHibernate versus ADO.NET [1 registro]</h3>
<p>Aqui a diferença é gigantesca sendo de <strong>quase 4000% a favor do NHibernate. </strong>Isso acontece, pois o NHibernate implementa cache nível 1 nativamente então dentro de uma mesma ISession o objeto é carregado apenas uma vez enquanto com ADO.NET é necessário ir ao banco e carregar o objeto diversas vezes.</p>
<h1>Conclusões</h1>
<p>Olhando para os números apenas, em casos onde diversos registros precisam ser carregados, ADO.NET nativo oferece uma performance superior e parece ser a escolha óbvia. No entanto:</p>
<ul>
<li>Os testes com NHibernate foram executados utilizandos exemplos simples e sem qualquer tipo de otimização. </li>
<li>NHibernate oferece nativamente cache de resultados de queries e cache nível 2 que se utilizados iriam exibir um resultado bem próximo ao cenário “<em>NHibernate versus ADO.NET [1 registro]” </em>onde o NHibernate é 4 vezes mais rápido. </li>
<li>ADO.NET oferece um custo de desenvolvimento e manutenção altissimo e este custo torna-se ainda maior se utilizado com Stored Procedures que transformam o cenário em algo totalmente caótico de gerenciar devido a dificuldade de manter a rastreabilidade desses diabinhos malignos. </li>
</ul>
<p>No caso de sistemas <a title="OLTP @ Wikipedia" href="http://pt.wikipedia.org/wiki/OLTP">OLTP</a> onde as transações carregam unidades individuais e/ou pequenas coleções de entidades por sessão, NHibernate não só é mais rápido como também oferece muito mais flexibilidade pra lidar com praticamente todos os cenários existentes. <a title="25 reasons not to write your own ORM @ Ayende&#39;s Blog" href="http://ayende.com/Blog/archive/2006/05/12/25ReasonsNotToWriteYourOwnObjectRelationalMapper.aspx">Este post do Ayende</a> mostra 25 funcionalidades importantes (cache, gerenciamento de concorrência, etc) que você vai precisar quando estiver lidando com dados e que custariam muito caro (tempo e complexidade) caso você queira escreve-las “na mão”.</p>
<p>Em cenários de aplicações de internet onde o número de leituras é infinitamente superior ao número de escritas no banco de dados deve se utilizar cache no front end (IIS), portanto o tempo que se leva pra montar uma página é irrelevante. Mesmo que você carregasse os dados de um servidor remoto via conexão discada não faria diferença uma vez que os dados estivessem em cache.</p>
<p>Por último, se você se encontrar em uma situação utilizando NHibernate onde o acesso a dados é o gargalo da sua aplicação seu problema não é o NHibernate (a não ser que você tenha usado-o de maneira totalmente absurda, mas a probabilidade de você fazer o mesmo com ADO.NET é grande também). Nestes cenários o problema não é o acesso a dados em si, mas o resto da arquitetura que não escala de maneira adequada seja por meio de cache, processamento assincrono, filas, etc.</p>
<p>Sendo assim, acredito que podemos concluir que não faz sentido algum no meio do ano de 2010 utilizar queries AdHoc ou Stored Procedures em aplicações <a title="Line of Business @ Wikipedia" href="http://en.wikipedia.org/wiki/Line_of_business">LoB</a>. <img src='http://blog.tucaz.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>O código completo utilizado está no GitHub e pode ser <a title="NHPerf Source Code @ GitHub" href="http://github.com/tucaz/Samples/tree/master/NHPerf/">acessado online</a> ou baixado em <a title="Download of NHPerf Source Code @ GitHub" href="http://github.com/downloads/tucaz/Samples/NHPerf.zip">formato zip</a>.</p>
<p><strong>[1] – Hidratação é o processo de preenchimento (filling) das propriedades de uma entidade</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tucaz.net/2010/08/31/performance-nhibernate-versus-ado-net/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Como gerenciar versões de banco de dados &#8211; Parte 2</title>
		<link>http://blog.tucaz.net/2009/03/08/como-gerenciar-versoes-de-banco-de-dados-parte-2/</link>
		<comments>http://blog.tucaz.net/2009/03/08/como-gerenciar-versoes-de-banco-de-dados-parte-2/#comments</comments>
		<pubDate>Sun, 08 Mar 2009 03:42:17 +0000</pubDate>
		<dc:creator>tucaz</dc:creator>
				<category><![CDATA[Banco de Dados]]></category>
		<category><![CDATA[migrations]]></category>
		<category><![CDATA[Migrator.NET]]></category>

		<guid isPermaLink="false">http://blog.tucaz.net/?p=255</guid>
		<description><![CDATA[Utilizando Migrator.NET no gerenciamento de versões de banco de dados.]]></description>
			<content:encoded><![CDATA[<p>Na <a title="Como gerenciar versões de banco de dados - Parte 1" href="http://blog.tucaz.net/2009/03/01/como-gerenciar-versoes-de-banco-de-dados-parte-1/" target="_self">primeira parte</a> falei um pouco dos problemas envolvidos no controle de versionamento de banco de dados. Agora esta na hora de apresentar alguma solução, certo? <img src='http://blog.tucaz.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Apresentando Migrator.NET</strong></p>
<p>Para resolver a maioria (senão todos) os problemas de versionamento de banco temos uma ferramenta maravilhosa chamada<a title="Migrator.NET - Google Code" href="http://code.google.com/p/migratordotnet/" target="_self"> Migrator.NET</a>. Essa ferramenta é um port para .NET do original em <a title="RoR Migrations" href="http://api.rubyonrails.org/classes/ActiveRecord/Migration.html" target="_self">Rails</a>. A idéia por trás dela é bastante simples: consiste em diversos objetos (classes) versionados (da mesma maneira que código normal) contendo as instruções que devem ser executadas para gerar e/ou voltar o schema do banco de dados. Cada classe corresponde a uma instrução de alteração e contém um método Up (adicionar/avançar) e um método Down (retroceder/fallback) equivalente. Vejamos como é facil no exemplo abaixo:</p>
<pre name="code" class="c-sharp">#region Usings

using System.Data;
using Migrator.Framework;

#endregion

namespace NetScrum.Migrations.Tables
{
    [Migration(20090209211900)]
    public class CreateTableProject : Migration
    {
        public override void Down()
        {
            Database.RemoveTable("netscrum_project");
        }

        public override void Up()
        {
            Database.AddTable("netscrum_project",
                new Column("id", DbType.Int32, ColumnProperty.Identity)
                , new Column("name", DbType.AnsiString, 100, ColumnProperty.NotNull)
                , new Column("description", DbType.AnsiString, 300, ColumnProperty.Null)
                );

            Database.AddPrimaryKey("pk_project", "netscrum_project", "id");
        }
    }
}</pre>
<p>Viram? Basta referenciar a DLL <strong>Migrator.Framework.dll</strong>, adicionar a diretiva <strong>using</strong> criar sua classe herdando de <strong>Migration</strong> e dar override nos métodos <strong>Up</strong> e <strong>Down</strong>.</p>
<p><strong>Gerenciando as versões</strong></p>
<p>Para gerenciar as versões e garantir que os migrations sejam executados na ordem correta, você deve utilizar o atributo <strong>Migration(long version)</strong> decorando a classe. Você deve preenche-lo com um long contendo o timestamp no formato AAMMDDhhmmss (ano/mes/dia/hora/minuto/segundo) em que seu migration foi gerado. Ou seja, um alter table da tabela projeto, por exemplo, deve conter um valor mais novo (maior) que o create table correspondente para que o migration de create seja executado antes do alter.</p>
<p><strong>Configurando o build</strong></p>
<p>Criar e gerenciar migrations é muito fácil. No entanto, as configurações dele são um pouquinho chatas para quem não está familizarizado com <a title="MSBuild Reference - MSDN.com" href="http://msdn.microsoft.com/pt-br/library/0k6kkbsd.aspx" target="_self">MSBuild</a> ou <a title="NAnt - Sourceforge" href="http://nant.sourceforge.net/" target="_self">NAnt</a>. Neste artigo vamos usar o MSBuild que já é nativo e eu gosto mais simplesmente por estar familiarizado.</p>
<p>Junto com o código fonte compilado do Migrator.NET vem também o assembly <strong>Migrator.MSBuild.dll </strong>que é onde está a o target especifico que o MSBuild precisa para executar os migrations. Este target será usado no arquivo de build (explicado mais abaixo) e deve ser configurado como o exemplo abaixo apontando para o caminho onde esta o assembly. Arquivos Migrator.Targets:</p>
<pre name="code" class="xml">

        $(MigratorTasksPath)\Migrator.MSBuild.dll</pre>
<p>A propriedade <em>$(MigratorTasksPath)</em> define onde está o assembly Migrator.MSBuild.dll. O valor desta propriedade pode ser hard-coded ou então preenchida no arquivo de build conforme veremos.</p>
<p>Por padrão, todo projeto (arquivo.csproj no caso de C#) é um arquivo de MSBuild. É possível editá-lo para incluir as configurações necessárias ao Migrations, mas cedo ou tarde é perigoso que Visual Studio o recrie ou o modifique a seu bel prazer e ai perderiamos as customizações. Portanto, prefiro criar um outro arquivo de build exclusivo para os migrations e chama-lo quando eu bem entender. Segue abaixo o arquivo NetScrum.Migrations.build:</p>
<pre name="code" class="xml">

    $(MSBuildProjectDirectory)</pre>
<p>Este arquivo define uma série de paramêtros:</p>
<ul>
<li>MigratorTasksPath &#8211; Caminho utilizado para apontar onde esta o target (mencionado acima). Neste caso, é preenchido pela propriedade $(MSBuildProjectDirectory) que aponta para onde o arquivo build que está sendo chamado está localizado.</li>
<li>DatabaseVersion &#8211; Será passado via paramêtro na hora da chamada do Migrator.NET. Caso não seja informado, o valor default é -1 que indica para a última versão.</li>
<li>Provider = Banco de dados de destino. Neste caso estamos usando SqlServer, mas Migrator.NET funciona para <a title="Bancos suportados pelo Migrator.NET" href="http://code.google.com/p/migratordotnet/" target="_self">outros bancos também</a>.</li>
<li>Connectionstring &#8211;  Óbvio, né? <img src='http://blog.tucaz.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>To &#8211; Recebe o valor do parametro DatabaseVersion indicando a versão de destino do migrations.</li>
<li>Migrations &#8211; Caminho onde se encontra o assembly compilado contendo as migrations.</li>
</ul>
<p>Existem alguns outros paramêtros que permitem uma configuração um pouco diferenciada, como por exemplo, ao invés de fornecer o assembly compilado apenas informar o caminho onde estão as classes para que o próprio Migrator.NET faça a compilação.</p>
<p>Uma vez que tudo esteja configurado, basta ir até o command prompt, navegar até a pasta onde o arquivo.build e chamar o MSBuild passando os paramêtros conforme o exemplo abaixo:</p>
<pre name="code" class="brush: shell">%windir%\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe NetScrum.Migrations.build /t:Migrate /p:DatabaseVersion=-1</pre>
<p>Os paramêtros são:</p>
<ul>
<li>NetScrum.Migrations.build &#8211; Nome do arquivo de build que contém as configurações do Migrator.NET</li>
<li>/t:Migrate &#8211; Target que deve ser executado. Neste caso o target de migrations <img src='http://blog.tucaz.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>/p:DatabaseVersion=-1 &#8211; Versão do banco para qual desejo ir. Caso queira ir para última versão é só informar -1. Caso queira zerar o banco (executar Down de todas as migrations) é só informar 0. No caso de ir para uma versão específica é só informar o timestamp desejado.</li>
</ul>
<p>É isso! Configurar a primeira vez é um pouco chato. Acertar os caminhos dos arquivo requer algumas tentativas para quem não está familizarizado com o MSBuild, mas nada muito traumático. Nos exemplos, todos os arquivos necessários (menos o assembly contendo as migrations) estavam na mesma pasta (tools) para facilitar.</p>
<p><strong>Exemplo</strong></p>
<p>Quem quiser ver o exemplo funcionando, basta baixar a <a title=".NET Scrum" href="http://netscrum.codeplex.com/" target="_self">última versão do .NET Scrum</a>. Ele contém as pastas e arquivos configurados direitinho pra funcionar.</p>
<p><strong>Importante</strong></p>
<p>A versão utilizada para este artigo foi a 0.8 que baixei tem uns 45 dias. Na época, apesar de compilada não estava funcionando então tive que efetuar umas pequenas correções do trunk. Não testei a versão 0.8 disponível hoje, portanto você pode <a title="Migrator.NET 0.8" href="http://tucaz.net/downloads/Migrator_0.8.zip" target="_self">baixar aqui a versão 0.8 compilada e corrigida por mim</a>.</p>
<p><strong>Referências</strong></p>
<p>Até alguns dias atrás eu não tinha encontrado nenhum outro artigo a respeito deste assunto em português. Acredito que ainda não exista e esse seja o primeiro. Além das instruções básicas de banco que foram apresentadas no migration do exemplo ainda é possível criar PKs, FKs, executar Sql&#8217;s open text entre outros procedimentos não descritos aqui.</p>
<p>Vocês podem encontrar informações a respeito desses <a title="Escrevendo migrations" href="http://code.google.com/p/migratordotnet/wiki/WritingMigrations" target="_self">procedimentos no site do projeto</a> ou tirar dúvidas e perguntar aqui mesmo no blog.</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tucaz.net/2009/03/08/como-gerenciar-versoes-de-banco-de-dados-parte-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Como gerenciar versões de banco de dados &#8211; Parte 1</title>
		<link>http://blog.tucaz.net/2009/03/01/como-gerenciar-versoes-de-banco-de-dados-parte-1/</link>
		<comments>http://blog.tucaz.net/2009/03/01/como-gerenciar-versoes-de-banco-de-dados-parte-1/#comments</comments>
		<pubDate>Sun, 01 Mar 2009 19:19:52 +0000</pubDate>
		<dc:creator>tucaz</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Banco de Dados]]></category>
		<category><![CDATA[Controle de Versão]]></category>
		<category><![CDATA[CVS]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[SqlServer]]></category>
		<category><![CDATA[SVN]]></category>
		<category><![CDATA[TFS]]></category>
		<category><![CDATA[VSS]]></category>

		<guid isPermaLink="false">http://blog.tucaz.net/?p=250</guid>
		<description><![CDATA[Gerenciando versões de banco de dados de sistemas e produtos em desenvolvimento de software por meio do Migrator.NET.]]></description>
			<content:encoded><![CDATA[<p>Quando estamos desenvolvendo software, seja ele um produto com desenvolvimento contínuo (como o Wordpress, por exemplo) ou um sistema<strong> </strong>customizado para um cliente nos deparamos com um problema no mínimo chato de resolver: gerenciar as versões do banco de dados (tabelas, procedures, etc) que evoluem ao longo do projeto. Vou apresentar a  vocês em um artigo com duas partes uma solução que tem me trazido paz e segurança nos últimos tempos e que talvez possa te ajudar também.</p>
<p><strong>O problema</strong></p>
<p>Controlar o código fonte que é compilado pela nossa ferramenta de trabalho é uma tarefa que já foi bem complicada, mas que se tornou relativamente fácil com a evolução dos próprios editores de código (Visual Studio) e dos repositórios de código (<a title="Team Foundation Server" href="http://msdn.microsoft.com/en-us/teamsystem/dd408382.aspx" target="_self">TFS</a>, <a title="Subversion" href="http://subversion.tigris.org/" target="_self">SVN</a>, <a title="Concurrent Version System" href="http://www.nongnu.org/cvs/" target="_self">CVS</a>, etc). No entanto, não podemos dizer o mesmo dó código fonte que utilizamos para nossa aplicação acessar  bancos de dados. Na maioria da vezes esse código não é compilado e por mais que existam checagens de sintaxe os erros tendem a aparecer na hora que estamos desenvolvendo a versão 2.1 do sistema e precisamos recuperar versão 1.5 para corrigir bugs. Isto, quando esse controle é feito de alguma forma e esse processo é possível, pois na maioria das vezes tudo que as pessoas mantém são os dados no próprio <a title="Sistemas de Gerenciamento de Banco de Dados" href="http://pt.wikipedia.org/wiki/Sistema_de_gerenciamento_de_banco_de_dados" target="_self">SGBD </a>sem nenhum controle de versão.</p>
<p>Gerenciar a versão do banco de dados quer dizer que no momento em que eu recuperar a versão XYZ do meu sistema também vou conseguir recuperar os artefatos de banco (tabelas, procedures, triggers, etc) correspondentes a esta versão, restaurando desta forma o sistema em um ponto estável tanto do ponto de vista de estrutura quanto do ponto de vista de dados.</p>
<p>Além dos pontos falhos óbvios que essa falta de controle apresenta existe mais um problema que considero grave e que, inclusive prejudica a aplicação de práticas ágeis como integração contínua e testes automatizados. Existindo a necessidade de efetuar esse controle de maneira manual fica impraticável a execução dessas práticas, pois para executá-las durante todo o tempo <strong>tudo</strong> (incluindo os scripts de banco de dados) que compõe o sistema deve permitir automatização.</p>
<p><strong>As opções existentes<br />
</strong></p>
<p>É claro que não posso falar por toda a comunidade de desenvolvimento Microsoft, mas  a grande maioria dos projetos que já participei ou conversei a respeito com outros colegas de plataforma tinha pouquissimo (não confiável) ou nenhum controle deste tipo. Geralmente as pessoas efetuam este tipo de controle de duas formas:</p>
<ul>
<li><em>Como se fosse código-fonte normal</em> &#8211; Scripts de create table, procedures e demais artefatos são mantidos em diversos arquivos SQL (ou em um linguição) no repositório de código e o desenvolvedor utiliza eles na hora em que precisa avançar ou restaurar uma versão. O maior problema desta técnica é que como o desenvolvedor não precisa efetivamente gerar scripts de banco de dados para modificar o banco, pois pode faze-lo pela ferramenta RAD com arrasta-estica-e-puxa dificilmente ele gera esses scripts depois da primeira vez e mais raramente ainda ele gera esses scripts de maneira correta. No final, temos uma salada de scripts: alguns utilizando alter table, outros modificando um script de create já existente, diversas versões da mesma procedure e possívelmente nenhum daqueles scripts de carga feitos pelo joãozinho no começo do projeto. Dessa forma, é impossível ir para a versão de banco de dados desejada de maneira fácil e sem dores de cabeça.</li>
<li><em>Mantendo tudo no banco de dados</em> &#8211; A maioria dos desenvolvedores, infelizmente, se preocupa pouquissimo com o futuro do projeto e estão preocupados apenas com suas tarefas atuais. Dessa forma, qualquer atalho para terminar uma tela mais rápido é bem vindo, mesmo que este atalho cause um grande problema no futuro. Por este motivo, muitas pessoas mantem a estrutura de banco de dados apenas no SGBD. Alguns projetos inclusive não tem nem um modelo de dados em uma ferramenta como o ErWin ou DBDesigner por exemplo. Agora vamos imaginar que por algum motivo o banco de dados de desenvolvimento foi pro espaço. Se não tiver alguém da equipe que mantem um backup local o projeto está perdido. Possívelmente milhões $$$ perdidos por preguiça e falta de organização.</li>
</ul>
<p>A Microsoft tentou no <a title="VSTS Database Edition" href="http://msdn.microsoft.com/pt-br/library/aa833253.aspx" target="_self">Visual Studio Team System Database Edition</a> com o projeto de banco de dados (somente para SqlServer) uma alternativa a essas maneiras, mas infelizmente não obteve sucesso. A idéia é manter um projeto que por meio de um banco de dados local simula a compilação dos scripts diminuindo os erros de deploy. No entanto, todo este processo é lento, obriga o desenvolvedor a ter um SqlServer instalado localmente e tem uma série de limitações como não poder acessar outros bancos diferentes do banco com qual o sistema trabalha e de outros providers (Oracle, MySql, etc.). Ainda não testei o VSTS 2010, mas não acredito que seguindo esta receita seja possível obter muito sucesso.</p>
<p><strong>A solução</strong></p>
<p>Para resolver este problema, o ideal seria que pudéssemos tratar dos objetos de banco da mesma maneira que tratamos os objetos do nosso sistema. Objetos que compilam efetivamente nos oferecem mais segurança, ainda mais se estes forem construidos utilizando uma API simples e padronizada que possibilite o deploy em bancos distintos. Melhor ainda se o desenvolvedor não precisar ter muito trabalho para efetuar este controle, pois se o processo exigir muito trabalho ninguém irá utilizá-lo.</p>
<p>No <a title="Como gerenciar versões de banco de dados - Parte 2" href="http://blog.tucaz.net/2009/03/08/como-gerenciar-versoes-de-banco-de-dados-parte-2/" target="_self">próximo post</a>, vou falar sobre o <a title="Migrator.NET" href="http://code.google.com/p/migratordotnet/" target="_self">Migrator.NET</a> que oferece essas características que apresentei no paragráfo anterior de uma maneira rápida e fácil de usar. <img src='http://blog.tucaz.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><a title="Como gerenciar versões de banco de dados - Parte 2" href="http://blog.tucaz.net/2009/03/08/como-gerenciar-versoes-de-banco-de-dados-parte-2/" target="_self">Link para parte 2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.tucaz.net/2009/03/01/como-gerenciar-versoes-de-banco-de-dados-parte-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

