<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Add Watch!</title>
	<atom:link href="http://addwatch.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://addwatch.wordpress.com</link>
	<description>Tombos e curiosidades do dia-a-dia com desenvolvimento .NET..</description>
	<lastBuildDate>Thu, 05 Nov 2009 14:19:26 +0000</lastBuildDate>
	<language>pt-br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='addwatch.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Add Watch!</title>
		<link>http://addwatch.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://addwatch.wordpress.com/osd.xml" title="Add Watch!" />
	<atom:link rel='hub' href='http://addwatch.wordpress.com/?pushpress=hub'/>
		<item>
		<title>1º Coding Dojo DotNetFloripa &#8211; Diário de Bordo</title>
		<link>http://addwatch.wordpress.com/2009/06/18/1o-codingdojo-dotnetfloripa/</link>
		<comments>http://addwatch.wordpress.com/2009/06/18/1o-codingdojo-dotnetfloripa/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 00:40:53 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Coding Dojo]]></category>
		<category><![CDATA[Eventos]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=77</guid>
		<description><![CDATA[Salve pessoal! Ontem ocorreu o primeiro Coding Dojo do grupo DotNetFloripa. Acabei não anunciando aqui no blog (a lista de dois grupos me pareceu uma audiência um pouco maior ), mas ao menos os resultados ficarão registrados por aqui. A idéia do dojo surgiu numa troca de e-mails em que discutíamos possíveis temas de futuros [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=77&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Salve pessoal!</p>
<p>Ontem ocorreu o primeiro Coding Dojo do grupo DotNetFloripa. Acabei não anunciando aqui no blog (a lista de dois grupos me pareceu uma audiência um pouco maior <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ), mas ao menos os resultados ficarão registrados por aqui.</p>
<p>A idéia do dojo surgiu numa troca de e-mails em que discutíamos possíveis temas de futuros eventos do grupo e, como eu nunca havia ouvido falar da expressão (vcs realmente já haviam? <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ), saí pesquisando pelo Google, seguindo links, aquele processo habitual. Também habitualmente metido, enviei algumas sugestões e acabei abraçando a organização desse primeiro encontro. Muito gratificante!</p>
<div style="border:2px solid;background:#ffff99 none repeat scroll 0 0;text-align:justify;"><strong>Coding Dojo</strong>: evento onde um grupo de programadores, utilizando TDD e baby steps, tenta resolver um problema proposto de lógica. Todos dão pitacos e revezam-se no teclado e como &#8220;co-pilotos&#8221;, o que torna a interação muito maior. O grande objetivo não está na resolução do problema, mas sim na troca de informações e contato com novas idéias, tecnologias e formas de programar, o que sempre acaba agregando.</div>
<p>Não compareceram muitas pessoas (8 no total), o que acabou mostrando-se positivo no final do encontro. A interação e participação de todos ocorreu acima do esperado (pelo menos por mim), o que foi um dos pontos fortes do evento. Estava com um pé atrás pois nas reuniões do grupo que participei a interação do pessoal com o palestrante, no geral, não era das mais eloquentes. Nesse encontro, entretanto, todos contribuíram com idéias para o código, dúvidas e tudo mais. Como boa parte do pessoal ainda não utiliza TDD no dia a dia, boa parte do tempo foi utilizada discutindo alguns conceitos, explicando outros, etc, etc. Por este motivo acabamos não tendo tempo para concluir o problema, mas espero que não faltem próximas oportunidades.</p>
<p>No final, chegamos a uma lista de pontos positivos e outros que podemos melhorar para os próximos encontros:</p>
<p><strong><span style="color:#339966;">Pontos positivos</span></strong>:</p>
<ul>
<li>Número de participantes: mesmo não plenejadamente, foi consenso entre todos que um número de participantes maior que 10 pode inviabilizar a interação no dojo;</li>
<li>Prova do TDD: mesmo não tendo codificado tanto quanto deveríamos (construímos 4 métodos de teste) já foi possível exemplificar o valor do TDD quando, devido à alteração para um teste, outro anteriormente &#8220;green&#8221; passou a falhar;</li>
<li>Participação do pessoal: todos interagiram e sentaram-se pra programar, sem medo de ser feliz. Dicas de VS, frameworks, TDD, lógica e dúvidas surgiram aos montes. Muito legal;</li>
</ul>
<p><strong><span style="color:#993300;">Pontos a melhorar</span></strong>:</p>
<ul>
<li>Conceituação de TDD: pela pouca experiência de parte do pessoal com TDD, a maior parte do tempo foi utilizada em conceito ao invés de programação. Apesar de também ser positivo, o ideal seria fazermos uma palestra sobre TDD para que pudéssemos simplesmente praticá-lo no Dojo (obs.: a palestra já está sendo agendada);</li>
<li>Tempo de cada piloto: não houve um controle do tempo que cada um passava programando, o que dificultava as trocas num tempo &#8220;justo&#8221;. Foi sugerido que utilizemos uma abordagem &#8220;ping pong&#8221;, onde um desenvolvedor implementa um teste falho e o próximo faz o teste corrigir. Muito válido;</li>
<li>Piloto &#8220;type only&#8221;: em mais de uma situação a pessoa que estava programando simplesmente digitava o que os outros iam falando, não dando oportunidade ao piloto e ao co-piloto de decidirem por um passo antes de serem questionados. Talvez o ideal seja dar mais autonomia ao piloto/co-piloto (definição do próximo teste falho, por exemplo) para depois virem sugestões, questionamentos e tudo mais;</li>
<li>Resolução do problema: não conseguimos resolver o problema dentro do tempo previsto, se na próxima deixarmos ele sobreviver novamente vai virar questão de honra.. <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<p>Se alguém quiser ver o PPT com a descrição do problema que tentamos resolver + conceitos de Dojo e TDD + código desenvolvido, coloquei tudo no RapidShare pra baixar. É só <a href="http://rapidshare.com/files/246103559/1oCodingDojoDotNetFloripa.rar">clicar aqui</a>. Abaixo segue uma das fotos tiradas por lá do pessoal interagindo:</p>
<p><img class="alignnone size-full wp-image-79" title="1oCodingDojoDotNetFloripa" src="http://addwatch.files.wordpress.com/2009/06/dsc07941_reduz.jpg?w=461&#038;h=307" alt="1oCodingDojoDotNetFloripa" width="461" height="307" /></p>
<p>Gostaria de agradecer ao pessoal do <a href="http://www.dotnetfloripa.net/">DotNetFloripa</a> que compareceu no encontro pela presença e interação, ao pessoal do <a href="http://dojofloripa.wordpress.com/">DojoFloripa</a> pelo feedback positivo e representação (1 dos participantes era de lá! <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ) e ao <a href="http://isanchez.net/">Ivan Sanchez</a> (ex-DojoFloripa, atualmente em Londres) que me ajudou a esclarecer várias dúvidas e tornar esse primeiro encontro possível.</p>
<p>Comentários de qualquer tipo são bem-vindos. Até o próximo Dojo!</p>
<p>José Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/77/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/77/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/77/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=77&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/06/18/1o-codingdojo-dotnetfloripa/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>

		<media:content url="http://addwatch.files.wordpress.com/2009/06/dsc07941_reduz.jpg" medium="image">
			<media:title type="html">1oCodingDojoDotNetFloripa</media:title>
		</media:content>
	</item>
		<item>
		<title>Rollback automático com NUnit</title>
		<link>http://addwatch.wordpress.com/2009/06/13/rollback-automatico-com-nunit/</link>
		<comments>http://addwatch.wordpress.com/2009/06/13/rollback-automatico-com-nunit/#comments</comments>
		<pubDate>Sat, 13 Jun 2009 19:56:57 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[NUnit]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[XtUnit]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=65</guid>
		<description><![CDATA[A situação é comum: você constrói um conjunto de testes unitários baseado em registros que estão salvos em um banco de dados e tudo funciona bem. O problema é que assim que os dados são alterados/apagados/inseridos pelo primeiro ciclo de testes, seus Asserts simplesmente deixam de funcionar &#8211; e você precisa de alguma maneira voltar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=65&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A situação é comum: você constrói um conjunto de testes unitários baseado em registros que estão salvos em um banco de dados e tudo funciona bem. O problema é que assim que os dados são alterados/apagados/inseridos pelo primeiro ciclo de testes, seus Asserts simplesmente deixam de funcionar &#8211; e você precisa de alguma maneira voltar a base ao seu estado original.</p>
<p>Bom, antes de qualquer coisa vamos deixar algo claro: provavelmente você não devesse estar dependendo de um banco de dados. Se você estiver testando sua camada de domínio, o ideal é que suas suas classes de controle consumam uma interface de suas classes DAO cuja dependência tenha sido injetada. Isto permitirá que você construa stubs de suas classes de acesso a dados, garantindo que seus testes rodarão rapidamente (e que você sempre tenha coragem para rodá-los!) e não dependam de um banco de dados para serem rodados.</p>
<p>Mas suponhamos que você tenha uma razão muito forte para querer depender de um banco de dados. Você pode estar testando a camada de acesso a dados em si, stressar seu database através de testes unitários ou simplesmente já possuir um conjunto muito grande de testes prontos que desencorajam o refactor (não é algo que você deva se orgulhar, mas coisas assim acontecem). Em qualquer um desses casos, você tem algumas opções:</p>
<ol>
<li>Escrever seus testes para que eles sejam auto-suficientes: uma boa prática, seguindo a &#8220;metodologia&#8221; AAA de testes unitários: Arrange, Act, Assert. Para alguns casos (com muitos registros envolvidos), entretanto, isto pode ser bastante trabalhoso (e demorado);</li>
<li>Criar um backup da base que você roda os testes e restaurá-lo constantemente: menos trabalhoso, mas longe do ideal. Mesmo automatizando o restore via código trabalho adicional associado sempre que os dados fossem efetivamente alterados (para adição de novos testes, por exemplo);</li>
<li>Recarregar os dados do database a partir de XML, DBF ou algo que o valha: uma opção legal e até bem difundida. Arquivos XML ou de qualquer outro tipo, entretanto, não são minha representação ideal de dados relacionais;</li>
<li>E por último, é claro, a opção que falaremos aqui: utilizar o <a href="http://weblogs.asp.net/rosherove/archive/2004/10/05/238201.aspx">XtUnit</a>, framework desenvolvido pelo Roy Osherove (uma espécie de bam-bam-bam dos testes unitários) que permite um rollback nos seus dados com um simples attribute de [DataRollBack].</li>
</ol>
<p><span id="more-65"></span>Utilizar o NUnitX é muito fácil. Para utilizá-lo, você só precisa de um teste unitário que faça acesso aos dados e dos passos a seguir:</p>
<ol>
<li>Baixe o assembly da página do próprio Roy (ou o código se você quiser entender como funciona) e adicione uma referência ao seu projeto de testes;</li>
<li>Adicione um <em>using</em> para o namespace do framework, pra facilitar a utilização dos attributes:
<div style="background:white none repeat scroll 0 0;font-family:Courier New;font-size:10pt;color:black;">
<p style="margin:0;"><span style="color:#2b91af;"> 10</span> <span style="color:blue;">using</span> TeamAgile.ApplicationBlocks.Interception.UnitTestExtensions;</p>
</div>
</li>
<li>Herde sua classe de testes de ExtensibleFixture:
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 14</span> [<span style="color:#2b91af;">TestFixture</span>]</p>
<p style="margin:0;"><span style="color:#2b91af;"> 15</span> <span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NullableTests</span> : <span style="color:#2b91af;">ExtensibleFixture</span></p>
</div>
</li>
<li>Coloque o attribute de DataRollBack em um de seus métodos que fazem acesso a dados:
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 71</span> [<span style="color:#2b91af;">Test</span>]</p>
<p style="margin:0;"><span style="color:#2b91af;"> 72</span> [<span style="color:#2b91af;">DataRollBack</span>]</p>
<p style="margin:0;"><span style="color:#2b91af;"> 73</span> <span style="color:blue;">public</span> <span style="color:blue;">void</span> PersistNullablePersonWithNullValue()</p>
<p style="margin:0;"><span style="color:#2b91af;"> 74</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;"> 75</span> <span style="color:green;">// acesso a dados e tudo mais</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 76</span> }</p>
</div>
</li>
</ol>
<p>E pronto! Basta rodar seus testes e ver que seus dados permanecem inalterados mesmo após todos aqueles INSERTs, UPDATEs e DELETEs. Mas como isso acontece? Por trás dos panos o XtUnit utiliza técnicas de orientação a aspectos pra interceptar o início e o fim de cada método de teste, criando uma transação distribuída (garanta que seu MSDTC esteja ativado e corretamente configurado!) e fazendo o rollback no final. Como a transação é distribuída, mesmo que você envolva diferentes bancos de dados tudo vai ser desfeito no final do teste.</p>
<p>É claro que tanto poder traz alguns efeitos colaterais. Diria que &#8220;leve&#8221; não é a palavra mais apropriada para definir a maneira como a inalteração dos dados é controlada. Mas a praticidade certamente compensa para um conjunto limitado de testes. Por isso, use com moderação!</p>
<p>Abraços e até a próxima!</p>
<p>José Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/65/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=65&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/06/13/rollback-automatico-com-nunit/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>
	</item>
		<item>
		<title>Transformando DataSet para Excel através de XSL</title>
		<link>http://addwatch.wordpress.com/2009/06/03/transformando-dataset-para-excel-atraves-de-xsl/</link>
		<comments>http://addwatch.wordpress.com/2009/06/03/transformando-dataset-para-excel-atraves-de-xsl/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 00:17:25 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ADO.NET]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Xml]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=60</guid>
		<description><![CDATA[Desde a época que comecei a trabalhar com desenvolvimento (e lá se vão mais de 5 anos ) transformar informações carregadas do banco de dados em Excel é uma tarefa presente. Naquela época o sistema era feito em Delphi 5 e utilizávamos uma classe que encapsulava o objeto COM do próprio Excel. O programador que [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=60&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Desde a época que comecei a trabalhar com desenvolvimento (e lá se vão mais de 5 anos <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ) transformar informações carregadas do banco de dados em Excel é uma tarefa presente. Naquela época o sistema era feito em Delphi 5 e utilizávamos uma classe que encapsulava o objeto COM do próprio Excel. O programador que quisesse aquela funcionalidade em sua tela de exportação, com seu próprio layout de arquivo, tinha que realizar loops aninhados e desbravar o mundo dos objetos não tipados (tipo <em>var</em> no Delphi) pra conseguir setar cores, dados, fontes, formato de número e tudo mais.</p>
<p>Já não desenvolvo mais em Delphi há algum tempo e provavelmente hoje exista algo mais simples pra criar arquivos Excel a partir de DataSets ou algo que o valha na linguagem (talvez até já existisse aquela época e eu que não conhecesse), mas a questão é que a demanda permanece e, mesmo no mundo .NET, as soluções utilizadas, em sua maioria, não são exatamente simples. Com esse post pretendo mostrar como criar arquivos Excel a partir de DataSets com ASP.NET de uma maneira bastante simples e direta.</p>
<p><span id="more-60"></span>Antes de por a mão na massa vamos entender o conceito da solução. <strong>Primeiro fato: DataSets podem ser tratados como arquivos XML</strong>. É claro que um DataSet extrapola em muito o simples conceito de um agrupado de propriedades tipadas, mas o fato é que eles podem ser serializados e desserializados para e de arquivos XML, e isto é o que nos importa para esta solução. Um DataSet serializado, sem suas informações de XSD, fica mais ou menos assim:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 1</span> <span style="color:blue;">&lt;?</span><span style="color:#a31515;">xml</span><span style="color:blue;"> </span><span style="color:red;">version</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">1.0</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">encoding</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">utf-8</span>&#8220;<span style="color:blue;"> ?&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 2</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">MeuDS</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 3</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">MeuDT</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 4</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">ID</span><span style="color:blue;">&gt;</span>1<span style="color:blue;">&lt;/</span><span style="color:#a31515;">ID</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 5</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Name</span><span style="color:blue;">&gt;</span>João<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Name</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 6</span> <span style="color:blue;"> &lt;/</span><span style="color:#a31515;">MeuDT</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 7</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">MeuDT2</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 8</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">ID</span><span style="color:blue;">&gt;</span>1<span style="color:blue;">&lt;/</span><span style="color:#a31515;">ID</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 9</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Name</span><span style="color:blue;">&gt;</span>João<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Name</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 10</span> <span style="color:blue;"> &lt;/</span><span style="color:#a31515;">MeuDT2</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 11</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">MeuDS</span><span style="color:blue;">&gt;</span></p>
</div>
<p><strong>Segundo fato: um arquivo Excel também pode ser gravado como XML</strong>. Desde a versão 2003 do Excel é possível gravar um arquivo Excel como um arquivo XML. A estrutura do arquivo gerado fica assim:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 1</span> <span style="color:blue;">&lt;?</span><span style="color:#a31515;">xml</span><span style="color:blue;"> </span><span style="color:red;">version</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">1.0</span>&#8220;<span style="color:blue;">?&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 2</span> <span style="color:blue;">&lt;?</span><span style="color:#a31515;">mso-application</span><span style="color:blue;"> </span><span style="color:gray;">progid=&#8221;Excel.Sheet&#8221;</span><span style="color:blue;">?&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 3</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">Workbook</span><span style="color:blue;"> </span><span style="color:red;">xmlns</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">urn:schemas-microsoft-com:office:spreadsheet</span>&#8220;</p>
<p style="margin:0;"><span style="color:#2b91af;"> 4</span> <span style="color:blue;"> &lt;!&#8211;</span><span style="color:green;"> &#8230; (outros namespaces default) </span><span style="color:blue;">&#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 5</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Worksheet</span><span style="color:blue;"> </span><span style="color:red;">ss:Name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">MeuDT</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 6</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Table</span><span style="color:blue;"> </span><span style="color:red;">ss:ExpandedColumnCount</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">3</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">ss:ExpandedRowCount</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">4</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 7</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Row</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 8</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Cell</span><span style="color:blue;"> </span><span style="color:red;">ss:StyleID</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">s62</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 9</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Data</span><span style="color:blue;"> </span><span style="color:red;">ss:Type</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">String</span>&#8220;<span style="color:blue;">&gt;</span>ID<span style="color:blue;">&lt;/</span><span style="color:#a31515;">Data</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 10</span> <span style="color:blue;"> &lt;/</span><span style="color:#a31515;">Cell</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 11</span> <span style="color:blue;"> &lt;!&#8211;</span><span style="color:green;"> demais células ocultadas </span><span style="color:blue;">&#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 12</span> <span style="color:blue;"> &lt;/</span><span style="color:#a31515;">Row</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 13</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Row</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 14</span> <span style="color:blue;"> &lt;!&#8211;</span><span style="color:green;"> demais linhas ocultadas </span><span style="color:blue;">&#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 15</span> <span style="color:blue;"> &lt;/</span><span style="color:#a31515;">Row</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 16</span> <span style="color:blue;"> &lt;/</span><span style="color:#a31515;">Table</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 17</span> <span style="color:blue;"> &lt;!&#8211;</span><span style="color:green;"> seções opcionais também ocultadas </span><span style="color:blue;">&#8211;&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 18</span> <span style="color:blue;"> &lt;/</span><span style="color:#a31515;">Worksheet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 19</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">Workbook</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Existem uma séries de outras tags que podem fazer parte do arquivo, responsáveis por formatação, planilhas que estão abertas, maximizadas, etc, etc. Para ver um arquivo completo, basta criar uma planilha, preencher com alguns dados/formatações e Salvar Como..</p>
<p>Voltando à solução: se tanto o DataSet quanto o arquivo Excel são arquivos XML, será que não seria possível transformar um no outro? Considerando sua estrutura hierárquica bastante semelhante (tabelas/planilhas, linhas e células), esta parece ser a melhor solução. Mas existe algo que auxilie nesse sentido? A resposta é sim, e esse algo chama-se <strong>XSL</strong>.</p>
<p>O termo XSL vem de E<em>x</em>tensible <em>S</em>tylesheet <em>L</em>anguage, e trata-se de uma linguagem que permite transformar um XML original em um formato qualquer. Como assim? De maneira resumida, o XSL permite a definição de tags que possuam uma lógica de filtro/iteração/reconhecimento para que para todo nodo de um XML seja gerado um novo texto, baseado num template. Em nosso caso isso implica, por exemplo, em dizer que todo elemento que esteja no segundo nível (MeuDT, MeuDT2) será uma nova planilha, cada nodo seguinte transforma-se em uma coluna e seus valores vão preenchendo as linhas. Pode parecer confuso, mas um XSL de exemplo ajuda a materializar:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 18</span> <span style="color:blue;"> &lt;</span><span style="color:#2b91af;">xsl:template</span><span style="color:blue;"> </span><span style="color:red;">match</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">/*</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 19</span> <span style="color:blue;"> &lt;</span><span style="color:#2b91af;">xsl:for-each</span><span style="color:blue;"> </span><span style="color:red;">select</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">/*/*</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 20</span> <span style="color:blue;"> &lt;</span><span style="color:#2b91af;">xsl:if</span><span style="color:blue;"> </span><span style="color:red;">test</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">not(preceding::*[name(current()) = name()])</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 21</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Worksheet</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 22</span> <span style="color:blue;"> &lt;</span><span style="color:#2b91af;">xsl:attribute</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">ss:Name</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 23</span> <span style="color:blue;"> &lt;</span><span style="color:#2b91af;">xsl:value-of</span><span style="color:blue;"> </span><span style="color:red;">select</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">local-name()</span>&#8220;<span style="color:blue;">/&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 24</span> <span style="color:blue;"> &lt;/</span><span style="color:#2b91af;">xsl:attribute</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 25</span> <span style="color:blue;"> &lt;</span><span style="color:#a31515;">Table</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Nesse pequeno trecho do XSL é realizado um <em>foreach</em> em todos os nodos do segundo nível e, para aqueles com nome diferente do anterior (para que ele não crie 1 planilha para cada linha do DataSet) é gerado um novo elemento WorkSheet com nome igual ao do nodo do primeiro nível (por causa do <em>template match=&#8221;/*&#8221;</em> logo acima). Pode parecer bastante confuso num primeiro momento, mas com alguns testes básicos tudo começa a fazer sentido. <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Você pode aprender mais sobre transformações XSL <a href="http://www.w3schools.com/xsl/">nesse link</a>.</p>
<p>Para realizar a transformação completa de um DataSet em um Excel você vai precisar de um XSD bem mais completo que o exemplificado acima, mas não se preocupe, no final do artigo existe um link para um projeto que criei onde você consegue um 100%. Na verdade o que fiz foi pegar o arquivo utilizado <a href="http://www.eggheadcafe.com/articles/20050404.asp">nesse blog</a> e realizar algumas modificações para que ele consiga gerar mais de um <em>DataTable</em> num mesmo <em>DataSet</em> (essa era uma limitação explicitada pelo próprio autor).</p>
<p>Criado o XSL, fica faltando somente o código da aplicação ASP.NET. O trecho de código é realmente simples e fica como esse abaixo:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 61</span> <span style="color:blue;">protected</span> <span style="color:blue;">void</span> Button2_Click(<span style="color:blue;">object</span> sender, <span style="color:#2b91af;">EventArgs</span> e)</p>
<p style="margin:0;"><span style="color:#2b91af;"> 62</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;"> 63</span> <span style="color:#2b91af;">DataSet</span> ds = <span style="color:blue;">this</span>.GetData(); <span style="color:green;">// retorna dados teste</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 64</span> <span style="color:green;">// limpa response</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 65</span> Response.ClearHeaders();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 66</span> Response.ClearContent();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 67</span> Response.Clear();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 68</span> <span style="color:green;">// informa que será um arquivo excel anexado</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 69</span> Response.ContentType = <span style="color:#a31515;">&#8220;application/vnd.ms-excel&#8221;</span>;</p>
<p style="margin:0;"><span style="color:#2b91af;"> 70</span> Response.AddHeader(<span style="color:#a31515;">&#8220;Content-Disposition&#8221;</span>, <span style="color:#a31515;">&#8220;attachment&#8221;</span>);</p>
<p style="margin:0;"><span style="color:#2b91af;"> 71</span> Response.Write(CreateWorkbook(ds)); <span style="color:green;">// envia o XML gerado para o cliente</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 72</span> Response.Flush();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 73</span> Response.End();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 74</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;"> 75</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 76</span> <span style="color:blue;">public</span> <span style="color:blue;">static</span> <span style="color:blue;">string</span> CreateWorkbook(<span style="color:#2b91af;">DataSet</span> ds)</p>
<p style="margin:0;"><span style="color:#2b91af;"> 77</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;"> 78</span> <span style="color:green;">// lê o XSL de um arquivo de recursos (Resources.Resource.Excel)</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 79</span> <span style="color:#2b91af;">XslCompiledTransform</span> xt = <span style="color:blue;">new</span> <span style="color:#2b91af;">XslCompiledTransform</span>();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 80</span> xt.Load(<span style="color:#2b91af;">XmlReader</span>.Create(<span style="color:blue;">new</span> <span style="color:#2b91af;">StringReader</span>(Resources.<span style="color:#2b91af;">Resource</span>.Excel)));</p>
<p style="margin:0;"><span style="color:#2b91af;"> 81</span> <span style="color:green;">// pega o XML do DataSet</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 82</span> <span style="color:#2b91af;">XmlDataDocument</span> xmlDataDoc = <span style="color:blue;">new</span> <span style="color:#2b91af;">XmlDataDocument</span>(ds);</p>
<p style="margin:0;"><span style="color:#2b91af;"> 83</span> <span style="color:#2b91af;">StringWriter</span> stw = <span style="color:blue;">new</span> <span style="color:#2b91af;">StringWriter</span>();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 84</span> <span style="color:green;">// transforma o XML jogando no StringWriter</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 85</span> xt.Transform(xmlDataDoc, <span style="color:blue;">null</span>, stw);</p>
<p style="margin:0;"><span style="color:#2b91af;"> 86</span> <span style="color:blue;">return</span> stw.ToString();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 87</span> }</p>
</div>
<p>Por questões de exemplificação o código está o mais simples possível. Como vocês podem perceber meu XSL ficou como um arquivo de recurso do projeto, pra facilitar a leitura. A performance da transformação é realmente surpreendente e muito superior a qualquer interação com objetos COM que você possa ter no seu projeto. Comprovado por experiência própria e por outros depoimentos que li sobre isso durante uma discussão semelhante que tivemos na lista do <a href="http://www.dotnetfloripa.net/">DotNetFloripa</a>.</p>
<p>O resultado é um arquivo Excel gerado com uma planilha por datatable e o título das colunas impresso, como mostrado pelo print abaixo. Para customizar (adicionar formatação, tirar o título, etc) basta que você salve um arquivo Excel, entenda a estrutura gerada por ele e replique com as informações necessárias no seu XSL. Acreditem, não é tarefa das mais complexas.</p>
<p><img class="alignnone size-full wp-image-61" title="ExcelXSL" src="http://addwatch.files.wordpress.com/2009/06/excel.png?w=352&#038;h=353" alt="ExcelXSL" width="352" height="353" /></p>
<p>Com uma estrutura razoavelmente organizada você consegue criar exportações diferenciadas de acordo com sua demanda sem precisar criar novas classes que interajam com objetos COM nem realizar novos deploys de seu software para isto. Um típico caso de desenvolvedor e clientes felizes, o quê mais querer? <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Para os interessados em reaproveitar o XSL, ou simplesmente ver um exemplo rodando, coloquei um website no RapidShare, como habitual. É só <a href="http://rapidshare.com/files/240549472/DataSetExcelXSL.rar">clicar aqui</a> para baixar.</p>
<p>Abraços e até a próxima!</p>
<p>José Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/60/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/60/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/60/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/60/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/60/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/60/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/60/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/60/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/60/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/60/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/60/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/60/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/60/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/60/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=60&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/06/03/transformando-dataset-para-excel-atraves-de-xsl/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>

		<media:content url="http://addwatch.files.wordpress.com/2009/06/excel.png" medium="image">
			<media:title type="html">ExcelXSL</media:title>
		</media:content>
	</item>
		<item>
		<title>NHibernate &#8211; Mapeando valores default como null: IUserType, IParameterizedType</title>
		<link>http://addwatch.wordpress.com/2009/05/21/nhibernate-mapeando-valores-default-como-null-iusertype-iparameterizedtype/</link>
		<comments>http://addwatch.wordpress.com/2009/05/21/nhibernate-mapeando-valores-default-como-null-iusertype-iparameterizedtype/#comments</comments>
		<pubDate>Thu, 21 May 2009 18:05:32 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[NHibernate]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=53</guid>
		<description><![CDATA[Fala pessoal! Faz um tempo que não escrevo (sempre o mesmo papinho), mas baterei o incrível recorde de 2 posts técnicos num mesmo mês com esta postagem, então minha motivação está lá em cima! Na verdade, este post servirá como guia para algumas coisas do trabalho, e isso acaba sendo um &#8220;motivador&#8221; e tanto.. Apesar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=53&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Fala pessoal!</p>
<p>Faz um tempo que não escrevo (sempre o mesmo papinho), mas baterei o incrível recorde de 2 posts técnicos num mesmo mês com esta postagem, então minha motivação está lá em cima! Na verdade, este post servirá como guia para algumas coisas do trabalho, e isso acaba sendo um &#8220;motivador&#8221; e tanto..</p>
<p>Apesar de ser a primeira vez que o tema será abordado aqui, acredito que todos que lêem o blog (ou mesmo os que aterrisam aqui esporadicamente) já tenham utilizado ou pelo menos ouvido falar do NHibernate. O NHibernate é um framework de mapeamento objeto relacional para .NET, portado do excelente Hibernate (Java), que facilita sua vida em gravar e recuperar objetos do banco de dados. Acaba ajudando também a manter uma OO mínima, já que sem isso o trabalho fica muito mais doloroso, o que também é muito positivo.. O NH permite mapear diversos tipos de colunas, trabalhar com chaves geradas automaticamente e mais uma infinidade de coisas que nem uma centena de posts conseguiriam cobrir.</p>
<p>O fato é que, nesta semana, caímos num problema com campos que possuem valores default. Contextualizando: possuímos uma grande aplicação que foi desenvolvida originalmente em .NET 1.1 e hoje encontra-se e .NET 2.0. Na época do 1.1, tipos &#8220;nullables&#8221; não passavam de um sonho e as pessoas arrumavam soluções criativas para contornar a questão: criando structs próprios, utilizando valores default, etc. As soluções não eram exatamente o sonho de nenhum desenvolvedor, mas, dada as restrições do framework, funcionavam bem desde que fosse mantida certa disciplina. Neste projeto a solução utilizada foi a de valores default. Alguns campos são inicializados com extremos de seu tipo (ex.: Int32.MinValue) enquanto outros assumem valores &#8220;mágicos&#8221; (ex.: -1, 03/03/0003). No momento da persistência, estes valores são tratados pela camada apropriada (aquela mesma citada por problemas de performance em <a href="http://addwatch.wordpress.com/2009/03/26/xmlserializer-e-sgenexe-melhorando-performance/" target="_blank">outro post</a>) e transformados em DbNull (ou vice-versa).</p>
<p><span id="more-53"></span>Tudo funcionava bem e ninguém pensava em refatorar este comportamento nesse exato momento, até que tivemos que construir uma segunda implementação da camada DAO para armazenamento de um banco de dados local. Como o banco local não poderia ser SQL Server (ao qual nossa DAL está bastante amarrada), a opção de persistência foi o NHibernate. Mapeamos as entidades e, depois de alguns refactors no código para deixá-lo mais &#8220;OO&#8221;, as coisas pareciam funcionar bem. Isto, é claro, até o momento que foi percebido que as colunas que antes eram salvas como null e recuperadas como valores default não estavam mais comportando-se dessa maneira, o que acabava deixando a lógica de negócio inconsistente em alguns pontos. Neste momento, tínhamos duas opções:</p>
<ol>
<li>Partir pra tipos Nullable. Isto consistiria em: a) alterar todas as entidades e a camada de persistência para trabalharem com tipos nullable, b) alterar as classes de negócio para não esperarem os valores, c) torcer pra não ter esquecido nada e não ter quebrado nenhuma lógica do sistema com isso (não temos testes unitários cobrindo o código);</li>
<li>Encontrar uma maneira de fazer o NHibernate entender que alguns valores deveriam ser mapeados como nulo sem ter que escrever muito código pra isso.</li>
</ol>
<p>Pela minha &#8220;imparcial&#8221; exposição das opções vocês devem concluir que optamos pelo segundo caminho. Pode parecer gambiarra à primeira vista, mas garanto que foi uma decisão baseada numa boa dose de pragmatismo: garantia de testes, falta de recursos e prazos apertados não são coisas muito fáceis de serem conciliadas num projeto realmente grande e complexo.</p>
<p>Feita a decisão, partiu-se para a pesquisa. Alguém da equipe citou a possibilidade de UserTypes. Já havia ouvido falar de UserTypes no NHibernate mas nunca havia olhado para uma implementação, muito menos criado um na prática. Depois de uma procura rápida, fiquei mais tranqüilo com os exemplos que encontrei: bastaria implementar uma interface (IUserType) cujos vários métodos já estavam implementados com um dos sites encontrados e modificar somente 2 métodos. Moleza! O problema é que os benditos UserTypes, que já tinham até sido prototipados para o sistema, exigiriam a criação de uma classe para cada tipo e valor default. Assim, teríamos que ter uma classe para inteiros com valor default -1, shorts com valor default -32768, outra para shorts com valor default -1, e assim por diante. Nada prático! Os desenvolvedores teriam que criar uma nova classe toda vez que descobrissem um novo tipo com valor default.</p>
<p>Com o problema de precisar criar uma dezena de classes para um problema tão simples, voltei pro Google. Dessa vez a pesquisa rendeu uma segunda interface que, quando implementada, permite setar parâmetros definidos via mapeamento que são passados para a classe. Voila! Com um UserType parametrizável, basta passarmos o tipo .NET que queremos mapear, qual tipo do banco de dados que ele corresponde (um Enum do próprio NH) e dizer o valor default que deve ser comparado para termos uma solução genérica, elegante e simples para toda a equipe de desenvolvimento: eles só precisarão alterar os arquivos de mapeamento minimamente para informar o valor default de cada campo.</p>
<p>Para mostrar como implementar o conceito, montei um exemplo com duas classes Person: NullablePerson e RegularPerson. A idéia com as duas classes é poder comparar exatamente o comportamente dos tipos nullable com a solução que utilizaremos. Isto também facilita um pouco a criação dos testes unitários. O código das classes é ridiculamente simples e ficou assim:</p>
<div style="background:white none repeat scroll 0 0;font-family:Courier New;font-size:10pt;color:black;">
<p style="margin:0;"><span style="color:#2b91af;">7</span> <span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">RegularPerson</span></p>
<p style="margin:0;"><span style="color:#2b91af;">8</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">9</span> <span style="color:blue;">public</span> <span style="color:blue;">int</span> ID { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">10</span> <span style="color:blue;">public</span> <span style="color:blue;">string</span> Name { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">11</span> <span style="color:blue;">public</span> <span style="color:blue;">short</span> Age { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">12</span> <span style="color:blue;">public</span> <span style="color:#2b91af;">DateTime</span> RegisterDate { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">13</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">14</span></p>
<p style="margin:0;"><span style="color:#2b91af;">15</span> <span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NullablePerson</span></p>
<p style="margin:0;"><span style="color:#2b91af;">16</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">17</span> <span style="color:blue;">public</span> <span style="color:blue;">int</span> ID { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">18</span> <span style="color:blue;">public</span> <span style="color:blue;">string</span> Name { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">19</span> <span style="color:blue;">public</span> <span style="color:blue;">short</span>? Age { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">20</span> <span style="color:blue;">public</span> <span style="color:#2b91af;">DateTime</span>? RegisterDate { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">21</span> }</p>
<p style="margin:0;"> </p>
</div>
<p>Percebam que a única diferença entre as classes é a utilização do símbolo ? depois dos tipos, que equivale à utilização de Nullable&lt;&gt;. A tabela do banco de dados que armazenará estas entidades (mesma tabela para ambas entidades) é igualmente simples:</p>
<pre>CREATE TABLE [dbo].[PERSON](
 [ID] [int] IDENTITY(1,1) PRIMARY KEY,
 [NAME] [varchar](100) NULL,
 [AGE] [smallint] NULL,
 [DT_REGISTER] [datetime] NULL
)</pre>
<p>Feito isto, basta o mapeamento do NHibernate para que as entidades possam ser salvas no banco de dados:</p>
<div style="background:white none repeat scroll 0 0;font-family:Courier New;font-size:10pt;color:black;">
<p style="margin:0;"><span style="color:#2b91af;">2</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">hibernate-mapping</span><span style="color:blue;"> </span><span style="color:red;">xmlns</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">urn:nhibernate-mapping-2.2</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">assembly</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">NHibernateEntity</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">namespace</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">NHibernateEntity</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">3</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">class</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">NullablePerson</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">table</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">PERSON</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">lazy</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">false</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">4</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">id</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">ID</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">ID</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Int32</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">unsaved-value</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">0</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">5</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">generator</span><span style="color:blue;"> </span><span style="color:red;">class</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">identity</span>&#8220;<span style="color:blue;"> /&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">6</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">id</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">7</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">property</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Name</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">= </span>&#8220;<span style="color:blue;">NAME</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">String</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">length</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">100</span>&#8220;<span style="color:blue;">/&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">8</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">property</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Age</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">= </span>&#8220;<span style="color:blue;">AGE</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Int16</span>&#8220;<span style="color:blue;"> /&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">9</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">property</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">RegisterDate</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">= </span>&#8220;<span style="color:blue;">DT_REGISTER</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">DateTime</span>&#8220;<span style="color:blue;"> /&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">10</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">class</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">11</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">hibernate-mapping</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Notem que este é o arquivo de mapeamento da classe NullablePerson. Com ela possui propriedades nullable, só com isto já funciona maravilhosamente bem. Para nossa classe RegularPerson, entretanto, precisamos criar uma estrutura que permita que valores default sejam transformados em null e vice-versa. Para isto, vamos criar uma classe chamada NullDefaultValueType, que implementará duas interfaces: IUserType e IParameterizedType. A primeira é responsável por permitir que nossa classe possa ser mapeada no arquivo do NHibernate como um tipo de qualquer coluna. A segunda, por sua vez, permite que parâmetros sejam mapeados no arquivo de configuração para serem passados para esta classe. Apesar da descrição parecer complexa, a solução é bastante lógica e linear, acompanhe na sequência.</p>
<p>Abaixo segue a declaração da classe com as implementações relevantes da interface IUserType. Os demais métodos foram omitidos por não adiconarem comportamento relevante ao nosso caso.</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;">14</span> <span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NullDefaultValueType</span> : <span style="color:#2b91af;">IUserType</span>, <span style="color:#2b91af;">IParameterizedType</span></p>
<p style="margin:0;"><span style="color:#2b91af;">15</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">16</span> <span style="color:blue;">private</span> <span style="color:#2b91af;">Type</span> Type { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">17</span> <span style="color:blue;">private</span> <span style="color:#2b91af;">DbType</span> DbType { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">18</span> <span style="color:blue;">private</span> <span style="color:blue;">string</span> DefaultValue { <span style="color:blue;">get</span>; <span style="color:blue;">set</span>; }</p>
<p style="margin:0;"><span style="color:#2b91af;">19</span></p>
<p style="margin:0;"><span style="color:#2b91af;">20</span> <span style="color:blue;">public</span> <span style="color:blue;">object</span> NullSafeGet(System.Data.<span style="color:#2b91af;">IDataReader</span> rs, <span style="color:blue;">string</span>[] names, <span style="color:blue;">object</span> owner)</p>
<p style="margin:0;"><span style="color:#2b91af;">21</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">22</span> <span style="color:blue;">object</span> value = rs.GetValue(rs.GetOrdinal(names[0]));</p>
<p style="margin:0;"><span style="color:#2b91af;">23</span> <span style="color:blue;">if</span> (value == <span style="color:#2b91af;">DBNull</span>.Value)</p>
<p style="margin:0;"><span style="color:#2b91af;">24</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">25</span> <span style="color:blue;">return</span> <span style="color:#2b91af;">Convert</span>.ChangeType(<span style="color:blue;">this</span>.DefaultValue, <span style="color:blue;">this</span>.Type);</p>
<p style="margin:0;"><span style="color:#2b91af;">26</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">27</span> <span style="color:blue;">else</span></p>
<p style="margin:0;"><span style="color:#2b91af;">28</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">29</span> <span style="color:blue;">return</span> value;</p>
<p style="margin:0;"><span style="color:#2b91af;">30</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">31</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">32</span></p>
<p style="margin:0;"><span style="color:#2b91af;">33</span> <span style="color:blue;">public</span> <span style="color:blue;">void</span> NullSafeSet(System.Data.<span style="color:#2b91af;">IDbCommand</span> cmd, <span style="color:blue;">object</span> value, <span style="color:blue;">int</span> index)</p>
<p style="margin:0;"><span style="color:#2b91af;">34</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">35</span> <span style="color:blue;">if</span> (<span style="color:#2b91af;">Convert</span>.ChangeType(<span style="color:blue;">this</span>.DefaultValue, <span style="color:blue;">this</span>.Type).Equals(value))</p>
<p style="margin:0;"><span style="color:#2b91af;">36</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">37</span> ((<span style="color:#2b91af;">IDataParameter</span>)cmd.Parameters[index]).Value = <span style="color:#2b91af;">DBNull</span>.Value;</p>
<p style="margin:0;"><span style="color:#2b91af;">38</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">39</span> <span style="color:blue;">else</span></p>
<p style="margin:0;"><span style="color:#2b91af;">40</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">41</span> ((<span style="color:#2b91af;">IDataParameter</span>)cmd.Parameters[index]).Value = value;</p>
<p style="margin:0;"><span style="color:#2b91af;">42</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">43</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">44</span> }</p>
</div>
<p>O que precisa ser notado neste trecho de código são as propriedades, que posteriormente serão inicializadas pela implementação da outra interface, e os dois métodos: o que retorna o valor para o NHibernate (NullSafeGet) verifica se o valor do banco de dados é nulo e, se este for o caso, retorna o valor default configurado no lugar. O método de set (NullSafeSet), por sua vez, faz o contrário: verifica se o valor recebido foi o valor default e salva como nulo no banco de dados. Isto permitiria, por exemplo, que objetos NullablePerson e RegularPerson interagissem com o mesmo objeto sem problema de compatibilidade: o que para um é nulo, para o outro é valor default, de maneira transparente e independente do banco de dados.</p>
<p>A implementação da segunda interface (IParameterizedType) é mais simples: basta implementarmos um métodos que receberá os parâmetros e setar nossas propriedades. Ficou assim:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;">176</span> <span style="color:blue;">public</span> <span style="color:blue;">void</span> SetParameterValues(System.Collections.<span style="color:#2b91af;">IDictionary</span> parameters)</p>
<p style="margin:0;"><span style="color:#2b91af;">177</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">178</span> <span style="color:blue;">this</span>.Type = <span style="color:#2b91af;">Type</span>.GetType(parameters[<span style="color:#a31515;">"Type"</span>].ToString(), <span style="color:blue;">true</span>);</p>
<p style="margin:0;"><span style="color:#2b91af;">179</span> <span style="color:blue;">this</span>.DbType = (<span style="color:#2b91af;">DbType</span>)<span style="color:#2b91af;">Enum</span>.Parse(<span style="color:blue;">typeof</span>(<span style="color:#2b91af;">DbType</span>), parameters[<span style="color:#a31515;">"DbType"</span>].ToString());</p>
<p style="margin:0;"><span style="color:#2b91af;">180</span> <span style="color:blue;">this</span>.DefaultValue = parameters[<span style="color:#a31515;">"DefaultValue"</span>].ToString();</p>
<p style="margin:0;"><span style="color:#2b91af;">181</span> }</p>
</div>
<p>Vejam que a recuperação dos parâmetros é bastante simples. No método estamos pegando os 3 parâmetros necessários para nossa classe funcionar corretamente e setando em propriedades privadas de nosso UserType. Depois disto, basta alterar o mapeamento das propriedades de RegularPerson para algo assim:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;">1</span> <span style="color:blue;">&lt;?</span><span style="color:#a31515;">xml</span><span style="color:blue;"> </span><span style="color:red;">version</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">1.0</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">encoding</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">utf-8</span>&#8220;<span style="color:blue;"> ?&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">2</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">hibernate-mapping</span><span style="color:blue;"> </span><span style="color:red;">xmlns</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">urn:nhibernate-mapping-2.2</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">assembly</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">NHibernateEntity</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">namespace</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">NHibernateEntity</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">3</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">class</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">RegularPerson</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">table</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">PERSON</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">lazy</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">false</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">4</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">id</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">ID</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">ID</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Int32</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">unsaved-value</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">0</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">5</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">generator</span><span style="color:blue;"> </span><span style="color:red;">class</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">identity</span>&#8220;<span style="color:blue;"> /&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">6</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">id</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">7</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">property</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Name</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">= </span>&#8220;<span style="color:blue;">NAME</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">type</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">String</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">length</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">100</span>&#8220;<span style="color:blue;">/&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">8</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">property</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Age</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">= </span>&#8220;<span style="color:blue;">AGE</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">9</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">type</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">NHibernateEntity.NullDefaultValueType, NHibernateEntity</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">10</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">param</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Type</span>&#8220;<span style="color:blue;">&gt;</span>System.Int16<span style="color:blue;">&lt;/</span><span style="color:#a31515;">param</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">11</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">param</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">DbType</span>&#8220;<span style="color:blue;">&gt;</span>Int16<span style="color:blue;">&lt;/</span><span style="color:#a31515;">param</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">12</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">param</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">DefaultValue</span>&#8220;<span style="color:blue;">&gt;</span>-32768<span style="color:blue;">&lt;/</span><span style="color:#a31515;">param</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">13</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">type</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">14</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">property</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">15</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">property</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">RegisterDate</span>&#8220;<span style="color:blue;"> </span><span style="color:red;">column</span><span style="color:blue;">= </span>&#8220;<span style="color:blue;">DT_REGISTER</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">16</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">type</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">NHibernateEntity.NullDefaultValueType, NHibernateEntity</span>&#8220;<span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">17</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">param</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">Type</span>&#8220;<span style="color:blue;">&gt;</span>System.DateTime<span style="color:blue;">&lt;/</span><span style="color:#a31515;">param</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">18</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">param</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">DbType</span>&#8220;<span style="color:blue;">&gt;</span>DateTime<span style="color:blue;">&lt;/</span><span style="color:#a31515;">param</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">19</span> <span style="color:blue;">&lt;</span><span style="color:#a31515;">param</span><span style="color:blue;"> </span><span style="color:red;">name</span><span style="color:blue;">=</span>&#8220;<span style="color:blue;">DefaultValue</span>&#8220;<span style="color:blue;">&gt;</span>03/03/0003<span style="color:blue;">&lt;/</span><span style="color:#a31515;">param</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">20</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">type</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">21</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">property</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">22</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">class</span><span style="color:blue;">&gt;</span></p>
<p style="margin:0;"><span style="color:#2b91af;">23</span> <span style="color:blue;">&lt;/</span><span style="color:#a31515;">hibernate-mapping</span><span style="color:blue;">&gt;</span></p>
</div>
<p>Apesar do mapeamento de NullablePerson permanecer exatamente o mesmo, vemos que as propriedades que requerem o tratamento de valores default ganharam alguns nodos a mais. Apesar deste pequeno acréscimo, o mapeamento para o restante da equipe foi facilitado ao máximo com apenas uma nova classe, totalmente parametrizável. Além disso, instâncias de NullablePerson e RegularPerson podem ser utilizadas em paralelo, sem problema. Isto é comprovado pelo teste unitário abaixo:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;">94</span> [<span style="color:#2b91af;">Test</span>]</p>
<p style="margin:0;"><span style="color:#2b91af;">95</span> <span style="color:blue;">public</span> <span style="color:blue;">void</span> PersistRegularPersonWithDefaultNullValue()</p>
<p style="margin:0;"><span style="color:#2b91af;">96</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;">97</span> <span style="color:#2b91af;">RegularPerson</span> p = <span style="color:blue;">new</span> <span style="color:#2b91af;">RegularPerson</span>();</p>
<p style="margin:0;"><span style="color:#2b91af;">98</span> p.Name = <span style="color:#a31515;">&#8220;Maria&#8221;</span>;</p>
<p style="margin:0;"><span style="color:#2b91af;">99</span> p.Age = <span style="color:#2b91af;">Int16</span>.MinValue;</p>
<p style="margin:0;"><span style="color:#2b91af;">100</span> p.RegisterDate = <span style="color:blue;">new</span> <span style="color:#2b91af;">DateTime</span>(3, 3, 3);</p>
<p style="margin:0;"><span style="color:#2b91af;">101</span></p>
<p style="margin:0;"><span style="color:#2b91af;">102</span> session.Save(p);</p>
<p style="margin:0;"><span style="color:#2b91af;">103</span></p>
<p style="margin:0;"><span style="color:#2b91af;">104</span> <span style="color:green;">// recupera uma NullablePerson pra ter certeza que realmente ficou nulo</span></p>
<p style="margin:0;"><span style="color:#2b91af;">105</span> <span style="color:#2b91af;">NullablePerson</span> p2 = session.Get&lt;<span style="color:#2b91af;">NullablePerson</span>&gt;(p.ID);</p>
<p style="margin:0;"><span style="color:#2b91af;">106</span></p>
<p style="margin:0;"><span style="color:#2b91af;">107</span> <span style="color:#2b91af;">Assert</span>.IsNull(p2.Age);</p>
<p style="margin:0;"><span style="color:#2b91af;">108</span> <span style="color:#2b91af;">Assert</span>.IsNull(p2.RegisterDate);</p>
<p style="margin:0;"><span style="color:#2b91af;">109</span> }</p>
</div>
<p>E é isso! Com este post vimos como os UserTypes no NHibernate podem nos ajudar a contornar situações aparentemente não suportadas pela ferramenta, além de poderem ser parametrizados pelos próprios arquivos de mapeamento. Para quem quiser o código completo junto com o conjunto de testes unitários, coloquei os projetos no RapidShare, basta <a href="http://rapidshare.com/files/235624803/NHibernateParameterizedUserType.rar" target="_blank">clicar aqui </a>para baixar.</p>
<p>Um abraço, bons códigos e até a próxima!</p>
<p>Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/53/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/53/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/53/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=53&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/05/21/nhibernate-mapeando-valores-default-como-null-iusertype-iparameterizedtype/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>
	</item>
		<item>
		<title>Testes Unitários com NUnit</title>
		<link>http://addwatch.wordpress.com/2009/05/02/testes-unitarios-com-nunit/</link>
		<comments>http://addwatch.wordpress.com/2009/05/02/testes-unitarios-com-nunit/#comments</comments>
		<pubDate>Sat, 02 May 2009 18:27:31 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[NUnit]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=47</guid>
		<description><![CDATA[Fala pessoal! As coisas têm estado bastante corridas nas últimas semanas, motivo pelo qual terminei o mês de abril com o impressionante número de 1 post. Mas em maio o objetivo é mudar isso: no mínimo 2, .. Nas últimas semanas tenho lido bastante sobre testes unitários, inversão de controle (e injeção de dependência), princípios [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=47&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Fala pessoal!</p>
<p>As coisas têm estado bastante corridas nas últimas semanas, motivo pelo qual terminei o mês de abril com o impressionante número de 1 post. Mas em maio o objetivo é mudar isso: no mínimo 2, <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ..</p>
<p>Nas últimas semanas tenho lido bastante sobre testes unitários, inversão de controle (e injeção de dependência), princípios SOLID e algumas outras práticas defendidas pela comunidade ALT.NET.</p>
<p>Apesar de testes unitários já serem tópico de atenção há muito tempo e eu ter uma clara noção de como eles funcionavam, tenho que admitir que nunca os havia utilizado na prática. Como um <a href="http://codebetter.com/blogs/karlseguin/archive/2009/04/27/the-7-phases-of-unit-testing.aspx">post do Karl Seguin</a>, via CodeBetter, nesta semana falou do assunto também e alguns projetos na empresa seriam bastante beneficiados, pensei: é hora de dar uma pesquisada e de quebra tirar a poeira do blog!</p>
<p>Pra demonstrar um projeto com testes unitários básicos eu vou utilizar o NUnit. O VS2008, na edição Team System, também pode fazer testes unitários, mas minha escolha baseia-se no fato de eu não apoiar o recorrente comportamento &#8220;anti open frameworks&#8221; da MS. Além do custo do VS ser absurdo, eu realmente gostaria de poder participar de uma comunidade cada vez mais ativa sem depender da MS pra tudo. Nesse quesito é indiscutível a superioridade do Java (na verdade de sua comunidade) sobre o .NET, e pra mim grande parte desta culpa pertence à MS..</p>
<p><span id="more-47"></span>Antes de tudo, você precisa baixar os assemblies do <a href="http://www.nunit.org/">NUnit</a>. Pra mostrar as funcionalidades básicas do NUnit vamos criar uma solução no VS com dois projetos: uma class library para as classes do projeto e outra com nossas classes de teste. Você até pode deixar seus testes no mesmo assembly de suas classes controladoras ou de domínio, mas isto adiciona uma dependência de sua aplicação ao assembly do NUnit na hora do deploy que não é legal.</p>
<p>Vamos criar um exemplo clássico: uma classe calculadora. Pra simplificar as coisas por aqui, vou criar só um método: Somar. Para os demais métodos seria simplemente repetir o processo. A interface de sua classe ficaria mais ou menos assim:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 7</span> <span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">Calc</span></p>
<p style="margin:0;"><span style="color:#2b91af;"> 8</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;"> 9</span> <span style="color:blue;">public</span> <span style="color:blue;">double</span> Soma(<span style="color:blue;">double</span> x, <span style="color:blue;">double</span> y)</p>
<p style="margin:0;"><span style="color:#2b91af;"> 10</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;"> 11</span> <span style="color:blue;">return</span> 0;</p>
<p style="margin:0;"><span style="color:#2b91af;"> 12</span> }</p>
<p style="margin:0;"><span style="color:#2b91af;">13</span> }</p>
</div>
<p>Você pode perceber que ambos o métodos não está retornando o cálculo correto, e isto foi intencional: a idéia é que os testes primeiro falhem pra depois corrigirmos os códigos das classes, bem TDD mesmo. Pode parecer estranho num primeiro momento mas isto garante que você desenvolva código baseado em testes que você sabe que eles tem que passar, o que acaba garantindo a qualidade do seu código (imaginando que você não fique com preguiça de escrever todos os testes, é claro).</p>
<p>Depois da interface da classe definida, vamos escrever nossa classe de testes. Basta criar uma classe normal na class library de testes, adicionar a referência ao assembly do NUnit e criar um método TestarSoma(). Todos os métodos de teste não devem ter parâmetros nem retornar nada (void). Isto vai permitir ao NUnit executar os testes de maneira atômica, ou seja: tudo que um teste precisa para rodar é seu próprio código. Nosso método de teste ficaria mais ou menos assim:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 27</span> [<span style="color:#2b91af;">Test</span>]</p>
<p style="margin:0;"><span style="color:#2b91af;"> 28</span> <span style="color:blue;">public</span> <span style="color:blue;">void</span> TestarSoma()</p>
<p style="margin:0;"><span style="color:#2b91af;"> 29</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;"> 30</span> <span style="color:#2b91af;">Calc</span> c = <span style="color:blue;">new</span> <span style="color:#2b91af;">Calc</span>();</p>
<p style="margin:0;"><span style="color:#2b91af;"> 31</span> <span style="color:blue;">double</span> res = c.Soma(2.5, 2.5);</p>
<p style="margin:0;"><span style="color:#2b91af;"> 32</span> <span style="color:#2b91af;">Assert</span>.AreEqual(5, res);</p>
<p style="margin:0;"><span style="color:#2b91af;"> 33</span> }</p>
</div>
<p>Os pontos de interesse nesse trecho de código são:</p>
<ol>
<li>O attribute [Test] no topo do método: esse attribute é o que diz ao NUnit que trata-se de um teste unitário que deve ser executado. Existem outras tags que o NUnit disponibiliza, permitindo informar que uma exceção é esperada, que o método ainda não está implementado, extensões para dar Rollback automático no seu BD, etc, etc. O [Test] é o básico;</li>
<li>A classe Assert: essa é uma classe que fica no namespace do NUnit (NUnit.Framework) que é responsável por dizer se o teste funcionou ou não: ela fornece métodos estáticos para comparar igualdade, diferença e uma série de outras possibilidades.</li>
</ol>
<p>Antes de rodar nosso projeto com o NUnit só precisamos de mais um passo: adicionar o attribute [TestFixture] à classe de testes. Isto indica ao NUnit que esta classe possui métodos de testes. A definição de sua classe ficará assim:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 9</span> [<span style="color:#2b91af;">TestFixture</span>]</p>
<p style="margin:0;"><span style="color:#2b91af;"> 10</span> <span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">CalcTest</span></p>
</div>
<p>Feito isto é hora de rodar nosso teste pela primeira vez. Abra o NUnit GUI na pasta de instalação ou através do menu iniciar, e através do menu File &gt; Open Project indique a .DLL de seu projeto de testes. O NUnit identificará suas classes e métodos de teste automaticamente. Clique no botão Run e seu resultado deverá ser semelhante ao print abaixo:</p>
<p><img class="alignnone size-full wp-image-50" title="nunit_erro" src="http://addwatch.files.wordpress.com/2009/05/nunit_erro.jpg?w=400&#038;h=300" alt="nunit_erro" width="400" height="300" /></p>
<p>Pelo NUnit GUI é possível perceber que nosso único teste implementado até o momento &#8211; TestarSoma &#8211; falhou. Pelos detalhes exibidos na parte direita da tela existe um detalhamento dizendo que o valor esperado era 5, mas foi retornado 0: o que já esperávamos, pois nosso método ainda não está implementado.</p>
<p>O próximo passo, então, é implementar o método da classe Calc para que nosso teste passe. Para isto, vamos alterar o método Soma para retornar o óbvio:</p>
<div style="font-family:Courier New;font-size:10pt;color:black;background:white;">
<p style="margin:0;"><span style="color:#2b91af;"> 9</span> <span style="color:blue;">public</span> <span style="color:blue;">double</span> Soma(<span style="color:blue;">double</span> x, <span style="color:blue;">double</span> y)</p>
<p style="margin:0;"><span style="color:#2b91af;"> 10</span> {</p>
<p style="margin:0;"><span style="color:#2b91af;"> 11</span> <span style="color:blue;">return</span> x+y;</p>
<p style="margin:0;"><span style="color:#2b91af;"> 12</span> }</p>
</div>
<p>Com o método implementado, basta compilar a solução e ir novamente ao NUnit GUI (que já atualiza o assembly automaticamente). Rodando novamente o teste, percebemos pela cor verde que o teste rodou com sucesso:</p>
<p><img class="alignnone size-full wp-image-51" title="nunit_sucesso" src="http://addwatch.files.wordpress.com/2009/05/nunit_sucesso.jpg?w=400&#038;h=300" alt="nunit_sucesso" width="400" height="300" /></p>
<p>E é isso! Com isto você já tem uma noção básica de como utilizar o NUnit para construir seus testes unitários. Existem uma série de outros attributes que podem facilitar, em muito, sua vida, mas isto é assunto para um próximo post.</p>
<p>Use e abuse de testes unitários com o NUnit e, no caso de dúvidas ou sugestões de temas que você gostaria de ver por aqui é só entrar em contato!</p>
<p>Abraços, bons testes e até o próximo post!</p>
<p>Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/47/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=47&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/05/02/testes-unitarios-com-nunit/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>

		<media:content url="http://addwatch.files.wordpress.com/2009/05/nunit_erro.jpg" medium="image">
			<media:title type="html">nunit_erro</media:title>
		</media:content>

		<media:content url="http://addwatch.files.wordpress.com/2009/05/nunit_sucesso.jpg" medium="image">
			<media:title type="html">nunit_sucesso</media:title>
		</media:content>
	</item>
		<item>
		<title>Code Profile com Visual Studio 2008</title>
		<link>http://addwatch.wordpress.com/2009/04/09/code-profile-com-visual-studio-2008/</link>
		<comments>http://addwatch.wordpress.com/2009/04/09/code-profile-com-visual-studio-2008/#comments</comments>
		<pubDate>Thu, 09 Apr 2009 21:53:21 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=38</guid>
		<description><![CDATA[Olá pessoal! Performance de aplicações sempre foi e continuará sendo causa de muita discussão &#8211; e invariavelmente de muitos problemas também. Até pouco tempo atrás, pensar em profile de código era tido quase que como inviável, dada a complexidade e quantidade de recursos exigidas por este tipo de ferramenta. O Visual Studio 2008 trouxe um [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=38&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Olá pessoal!</p>
<p>Performance de aplicações sempre foi e continuará sendo causa de muita discussão &#8211; e invariavelmente de muitos problemas também.</p>
<p>Até pouco tempo atrás, pensar em profile de código era tido quase que como inviável, dada a complexidade e quantidade de recursos exigidas por este tipo de ferramenta.</p>
<p>O Visual Studio 2008 trouxe um recurso de profile de código muito interessante, possibilitando em poucos cliques é possível descobrir os pontos de seu código que estão consumindo mais recursos e otimizá-los.</p>
<p>Como o conjunto de recursos é razoável, demoraria um bocado pra escrever um post completo, então resolvi criar um vídeo com os principais pontos. Já aproveito e testo a aceitação do recurso por aqui.</p>
<embed src='http://widgets.vodpod.com/w/video_embed/ExternalVideo.806453' type='application/x-shockwave-flash' AllowScriptAccess='sameDomain' pluginspage='http://www.macromedia.com/go/getflashplayer' wmode='transparent' flashvars='c=v&v=5ad0cad0-a2de-498c-8871-617cc3c7aaa5&ifs=true&fr=msnvideo&mkt=pt-BR' width='480' height='360' />
<p>O código fonte da aplicação de teste, para os que quiserem reproduzir, pode ser baixado <a href="http://rapidshare.com/files/219445596/CodeProfilingBlog.rar">aqui</a>.</p>
<p>Para os que quiserem entender um pouco melhor, saiu na MSDN Magazine de março um <a href="http://msdn.microsoft.com/en-us/magazine/cc337887.aspx" target="_blank">artigo sobre o tema</a> (fonte de inspiração pra esse aqui <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).</p>
<p>Comentários e dúvidas sobre o assunto são incentivados, bem como a opinião sobre a utilização do vídeo no lugar do texto escrito.</p>
<p>Abraços e até a próxima!</p>
<p>Zé Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/38/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/38/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/38/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=38&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/04/09/code-profile-com-visual-studio-2008/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>
	</item>
		<item>
		<title>XmlSerializer e sGen.exe &#8211; Melhorando Performance</title>
		<link>http://addwatch.wordpress.com/2009/03/26/xmlserializer-e-sgenexe-melhorando-performance/</link>
		<comments>http://addwatch.wordpress.com/2009/03/26/xmlserializer-e-sgenexe-melhorando-performance/#comments</comments>
		<pubDate>Thu, 26 Mar 2009 21:22:43 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Xml]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=13</guid>
		<description><![CDATA[Utilizamos há algum tempo aqui na empresa uma camada caseira de acesso à dados que salva as configurações dos diferentes servidores e bancos de dados a serem acessados em um arquivo XML. Este arquivo XML, por sua vez, é lido pela biblioteca através da classe XmlSerializer (System.Xml.Serialization), que o transforma numa coleção de objetos com [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=13&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p style="text-align:justify;">Utilizamos há algum tempo aqui na empresa uma camada caseira de acesso à dados que salva as configurações dos diferentes servidores e bancos de dados a serem acessados em um arquivo XML. Este arquivo XML, por sua vez, é lido pela biblioteca através da classe XmlSerializer (System.Xml.Serialization), que o transforma numa coleção de objetos com apenas duas linhas de código.. simples e configurável, sempre nos pareceu uma excelente opção!</p>
<p style="text-align:justify;">Tudo corria bem até que um de nossos produtos começou a ganhar uma escala até então inédita para nós num único servidor, e a criação das classes de acesso a dados começou a ficar bastante lenta. Fuça daqui, revira de lá, chegou-se à conclusão que a serialização do bendito arquivo XML estava consumindo processamento demais. Como não suspeitamos do .NET Framework 1.1 (sim, ainda estávamos nele no ano passado), acabamos criando uma Factory que centralizava numa coleção estática todas coleções desserializadas pela aplicação, realizando o controle da modificação do arquivo através da classe FileSystemWatcher (System.IO). A performance melhorou e tudo parecia estar mais uma vez sob controle..</p>
<p style="text-align:justify;">Como nada dura para sempre, entretanto, aconteceu desta mesma camada de acesso a dados ter problemas com concorrência. Coincidentemente, no meio dessa análise de concorrência, ocorreu também de eu receber um link para o recurso de profiling de código do VSTS (assunto para um próximo post) e, adivinhem, não é que a leitura do XML continuava consumindo tempo demais?</p>
<p style="text-align:justify;">Tudo bem que a performance dificilmente estaria ligada aos problemas de concorrência, mas era preciso entender o porquê daquilo. Procedimento padrão: Google -&gt; XmlSerializer performance e&#8230; batata! Caí num <a title="XmlSerializer Performance Issue - Jin Nakashima" href="http://seewinapp.blogspot.com/2005/09/xmlserializer-performance-issue.html" target="_blank">artigo</a> sobre um problema de performance com o XmSerializer e seus workarounds para os frameworks 1.1 e 2.0+. O que acontece, em resumo, é o seguinte:</p>
<ul style="text-align:justify;">
<li>Ao criar uma instância da classe XmlSerializer com os construtores XmlSerializer(type) ou XmlSerializer(type, string), o .NET Framework cria automaticamente o serializador e desserializador daquele tipo, criando um assembly para armazená-lo (sim, isso mesmo, um assembly é criado em tempo de execução)..</li>
</ul>
<ul style="text-align:justify;">
<li>No .NET Framework 1.1, isto era feito à cada chamada do construtor, independente se aquele tipo já foi criado ou não! Incrível, não? Alguém se habilita pra chutar por que tínhamos problemas de performance? Existe um workaround no artigo que linkei acima para este caso, mas não testei por não ser o foco;</li>
</ul>
<ul style="text-align:justify;">
<li>Já no .NET Framework 2.0+, isto é feito assim que a classe é criada e o assembly é reutilizado no caso de reincidência de construção daquele tipo. Bem melhor, mas longe do ideal para sistemas em que a performance é crítica..</li>
</ul>
<p style="text-align:justify;">A grande melhoria de performance vem com o fato de que é possível, através de um utilitário de linha de comando chamado sGen.exe (acessível pelo VS promt) criar uma pré-compilação de todos esses tipos que vão ser serializados. É possível compilar todos os tipos de uma DLL ou somente alguns (<em>sgen MeuAssembly.dll</em>, para todos, por exemplo). Também é possível, nas opções de Build do projeto no próprio VS habilitar uma opção chamada<em> Generate Serialization Assembly</em>, que vai fazer exatamente o mesmo trabalho. Em ambos os casos, é gerado na pasta de build um arquivo com o nome MeuAssembly.XmlSerializers.dll, que quando jogado na sua pasta \bin reduz, e muito, o tempo de criação da classe XmlSerializer.</p>
<div style="border:2px solid;background:#ffff99 none repeat scroll 0 0;text-align:justify;"><span style="color:#ff0000;"><strong>ATENÇÃO</strong>:</span> O arquivo não será gerado caso seu Assembly possua classes ou tipos cujo nome coincida com tipos do .NET Framework ou mesmo existam duas classes com o mesmo nome em namespaces diferentes. Nesse caso, os tipos em questão devem ser decorados com os <em>attributes </em>de System.Xml.Serialization (XmlType em específico) para adquirir um nome ou namespace único! No caso de problemas, rode diretamente pelo sGen para ganhar mensagens mais detalhadas.</div>
<p style="text-align:justify;">É isso! Esta pode não ser uma situação das mais corriqueiras mas que pode destruir a performance de sua aplicação, então é sembre bom ficar atento!</p>
<p style="text-align:justify;">Abraços!</p>
<p style="text-align:justify;">Zé Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/13/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=13&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/03/26/xmlserializer-e-sgenexe-melhorando-performance/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>
	</item>
		<item>
		<title>Comeeeeça o jogo!</title>
		<link>http://addwatch.wordpress.com/2009/03/19/comeeeeca-o-jogo/</link>
		<comments>http://addwatch.wordpress.com/2009/03/19/comeeeeca-o-jogo/#comments</comments>
		<pubDate>Thu, 19 Mar 2009 21:39:50 +0000</pubDate>
		<dc:creator>José Filipe</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://addwatch.wordpress.com/?p=8</guid>
		<description><![CDATA[Começo a me preocupar comigo mesmo ao escrever um post mesmo sabendo que ninguém está lendo o blog.. O objetivo desse espaço é servir como um diário de bordo das andanças, tombos e lições aprendidas no dia-a-dia de tecnologia, principalmente .NET. Melhor assim, já que mesmo que ninguém visite o blog sei que vou poder [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=8&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Começo a me preocupar comigo mesmo ao escrever um post mesmo sabendo que ninguém está lendo o blog.. <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>O objetivo desse espaço é servir como um diário de bordo das andanças, tombos e lições aprendidas no dia-a-dia de tecnologia, principalmente .NET. Melhor assim, já que mesmo que ninguém visite o blog sei que vou poder salvar algum tempo de Google nas tão comuns situações de &#8220;<em>eu já vi isso. como se fazia mesmo?</em>&#8220;.</p>
<p>O nome do blog, certamente familiar pra alguns (aquelas aulas de criatividade não serviram pra nada mesmo), refere-se à funcionalidade de debug existente em IDEs pra acompanhar o valor de uma variável ao longo da execução. Mais uma tentativa pra ver se alguém assina o RSS Feed esperando encontrar coisas interessantes.. <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Agora que o gelo está quebrado, vem o primeiro post &#8220;as vera&#8221;! E, é claro, pra não fugir das frases prontas: sugestões, críticas e elogios são sempre muito bem-vindos..</p>
<p>Abraços!</p>
<p>Zé Filipe</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/addwatch.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/addwatch.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/addwatch.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/addwatch.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/addwatch.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/addwatch.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/addwatch.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/addwatch.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/addwatch.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/addwatch.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/addwatch.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/addwatch.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/addwatch.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/addwatch.wordpress.com/8/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=addwatch.wordpress.com&amp;blog=5539947&amp;post=8&amp;subd=addwatch&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://addwatch.wordpress.com/2009/03/19/comeeeeca-o-jogo/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/850ae6c880d39a497999b05ab48302bf?s=96&#38;d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96&#38;r=G" medium="image">
			<media:title type="html">jfneis</media:title>
		</media:content>
	</item>
	</channel>
</rss>
