<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-623104596848465773</id><updated>2011-11-01T11:28:45.492-02:00</updated><category term='clickonce'/><category term='poo'/><category term='public'/><category term='bug'/><category term='sony'/><category term='clob'/><category term='social'/><category term='sql dinamico'/><category term='delegation'/><category term='anti-spam'/><category term='publish'/><category term='virtual pc'/><category term='apostrofo'/><category term='entidade'/><category term='asp'/><category term='tabela temporaria'/><category term='debug'/><category term='silverbullet'/><category term='catch-all'/><category term='virtualbox'/><category term='dbo'/><category term='livemeeting'/><category term='ps3'/><category term='agregacao'/><category term='on the fly'/><category term='stored procedure'/><category term='mvc3'/><category term='hypervisor'/><category term='owner'/><category term='conversão'/><category term='fileshare'/><category term='game'/><category term='teletransporte'/><category term='aspas duplas'/><category term='sql server'/><category term='temporary table'/><category term='oracle'/><category term='aspas'/><category term='delegacao'/><category term='vmware player'/><category term='temp table'/><category term='contencao'/><category term='containment'/><category term='asp.net'/><category term='aggregation'/><category term='objetos'/><category term='ubuntu'/><category term='hospedagem'/><category term='ftp'/><category term='aspas simples'/><category term='sgbd'/><title type='text'>ImaginarTI</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-4615355004712782344</id><published>2011-07-28T13:23:00.000-03:00</published><updated>2011-07-28T13:23:19.506-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conversão'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='clob'/><title type='text'>CLOB e ORA-06502 - Por que e como corrigir</title><content type='html'>Ontem eu estava depurando uma procedure Oracle que faz a importação de dados de um sistema para outro. Essa procedure de importação gera log de tudo: dados importados, dados rejeitados, motivo de rejeição e etc. O log é todo armazenado em uma variável CLOB, que ao final do processo é anexada ao registro que armazena a execução da importação - foi executado na data tal, e o resultado foi tal.&lt;br /&gt;&lt;br /&gt;Ocorre que com o aumento da massa de dados a ser importada, começaram a aparecer erros ORA-06502 (PL/SQL: numeric or value error). Com a ajuda do PL/SQL Developer, consegui identificar que a exceção era gerada em uma linha que concatenava alguns valores na variável CLOB. Eu demorei algumas horas até me lembrar que uu já tinha visto esse erro devido à conversão implícita de string em número.&lt;br /&gt;&lt;br /&gt;Nessas horas foram algumas pesquisas na internet, até que achei um blog que me deu algumas dicas e a memória clareou (vou ficar devendo o crédito pois perdi o endereço do blog original).&lt;br /&gt;&lt;br /&gt;O fato é que na conversão implícita, o Oracle tenta converter tudo para NÚMERO. Isso é porque as operações com números (geralmente comparações, originadas de cláusulas WHERE) são muito mais rápidas que comparações de string. Só que apesar de mais rápido, é uma conversão menos segura, pois pode não funcionar em todos os casos. No nosso caso de CONCATENAÇÃO (e não de comparação), o Oracle tenta converter tudo para varchar, e nisso dá erro.&lt;br /&gt;&lt;br /&gt;Vamos a comprovação: Um laço que a cada volta, concatena um número em um CLOB.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="sourceCode"&gt;&lt;br /&gt;declare&lt;br /&gt;&amp;nbsp; &amp;nbsp; l_clob clob;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; for i in 1..50000&lt;br /&gt;&amp;nbsp; &amp;nbsp; loop&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; l_clob &amp;nbsp; := l_clob || 1;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- conversão implícita de número em varchar&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- força a conversão do blob em varchar também.&lt;br /&gt;&amp;nbsp; &amp;nbsp; end loop;&lt;br /&gt;&amp;nbsp; &amp;nbsp; dbms_output.put_line (length(l_clob));&lt;br /&gt;&lt;br /&gt;exception&lt;br /&gt;&amp;nbsp; &amp;nbsp; when others then&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dbms_output.put_line ('error: ' || sqlerrm);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dbms_output.put_line (length(l_clob));&lt;br /&gt;end;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Internamente o oracle converte esse CLOB em varchar, concatena com o 1 (também internamente já convertido em varchar), e armazena de volta na variável CLOB. Só que conforme a variável CLOB vai crescendo, chega um momento que fica maior que 32768 bytes (o limite de tamanho de varchar). Nessa hora, gera a exceção.&lt;br /&gt;&lt;br /&gt;Agora veja o exemplo abaixo, quase igual ao anterior. A diferença é que agora a concatenação é de uma string em um CLOB. Nesse caso o Oracle não faz a conversão do CLOB em varchar, e portanto não viola o limite do varchar. Logo, não dá erro!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="sourceCode"&gt;&lt;br /&gt;declare&lt;br /&gt;&amp;nbsp; &amp;nbsp; l_clob clob;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; for i in 1..50000&lt;br /&gt;&amp;nbsp; &amp;nbsp; loop&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; l_clob := l_clob || to_char(1);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- sem conversão implícita de número (ou datas),&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- a operação é entre varchar e clob. Neste caso,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- não há conversão do clob em varchar.&lt;br /&gt;&amp;nbsp; &amp;nbsp; end loop;&lt;br /&gt;&amp;nbsp; &amp;nbsp; dbms_output.put_line (length(l_clob));&lt;br /&gt;&lt;br /&gt;exception&lt;br /&gt;&amp;nbsp; &amp;nbsp; when others then&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dbms_output.put_line ('error: ' || sqlerrm);&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dbms_output.put_line (length(l_clob));&lt;br /&gt;end;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;É isso.&lt;br /&gt;Espero que sirva para ajudar mais alguém por aí.&lt;br /&gt;&lt;br /&gt;Abraços e até a próxima!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-4615355004712782344?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/4615355004712782344/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2011/07/clob-e-ora-06502-por-que-e-como.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/4615355004712782344'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/4615355004712782344'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2011/07/clob-e-ora-06502-por-que-e-como.html' title='CLOB e ORA-06502 - Por que e como corrigir'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-7927498050263398575</id><published>2011-07-22T14:13:00.001-03:00</published><updated>2011-07-22T14:14:53.118-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mvc3'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='hospedagem'/><title type='text'>ASP.NET MVC3 com Assemblies Privados</title><content type='html'>Esta semana eu precisei colocar um site novo no ar, no espaço de hospedagem da ImaginarTI. Curiosamente foi o primeiro site em ASP.NET MVC3 que vai para a nossa hospedagem - os demais ficaram hospedados diretamente nos clientes. O nosso provedor de hospedagem afirma que suporta MVC3, então achei que seria 100% transparente. Não foi bem assim...&lt;br /&gt;&lt;br /&gt;O fato é que após subir os arquivos, começaram a aparecer um monte de problemas. Modificamos o web.config para exibir os erros (só para debug do deloy mesmo) e vimos que eram assemblies faltando. Como assim faltando?&lt;br /&gt;&lt;br /&gt;Entrei em contato com o suporte da hospedagem e eles disseram que suportam o MVC 3, mas que eu tenho que colocar as DLL's no BIN. Ora, isso não é exatamente "suportar" MVC3, né? Me senti enganado (menos um ponto para esses caras), mas resolvi não brigar dessas vez. Bola para frente.&lt;br /&gt;&lt;br /&gt;Como resolver?&lt;br /&gt;Bem, o projeto (no VS2010) tinha sido criado com o template de projeto do próprio MVC, então todas as referências já estavam setadas corretamente. Bastou eu alterar algumas referências, mudando o COPY LOCAL para true, e acrescentar outras referências (também com COPY LOCAL true) e tudo voltou a funcionar.&lt;br /&gt;&lt;br /&gt;Não cheguei nem a procurar na internet, mas me lembro que o Scott Gu já tinha falado sobre isso. De qualquer forma, o que resolveu o meu caso foi:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Mudar o COPY LOCAL para True&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;System.Web.Helpers&lt;/li&gt;&lt;li&gt;System.Web.Mvc&lt;/li&gt;&lt;li&gt;System.Web.WebPages&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Novas referências&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Microsoft.Web.Infrastructure&lt;/li&gt;&lt;li&gt;System.Web.WebPages.Razor&lt;/li&gt;&lt;li&gt;System.Web.WebPages.Deployment&lt;/li&gt;&lt;li&gt;System.Web.Razor&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Tomara que ajude mais alguém por aí.&lt;/div&gt;&lt;div&gt;Até a próxima!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-7927498050263398575?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/7927498050263398575/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2011/07/aspnet-mvc3-com-assemblies-privados.html#comment-form' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/7927498050263398575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/7927498050263398575'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2011/07/aspnet-mvc3-com-assemblies-privados.html' title='ASP.NET MVC3 com Assemblies Privados'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-4707686070108286783</id><published>2011-07-04T14:44:00.001-03:00</published><updated>2011-07-04T14:45:14.748-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='asp'/><title type='text'>ASP x Asp.Net -- como explicar para leigos</title><content type='html'>Hoje um amigo aqui do trabalho, o &lt;a href="http://www.twitter.com/rochagasdiniz"&gt;Rodrigo Diniz&lt;/a&gt; (responsável pelo &lt;a href="http://extjsextendercontrol.codeplex.com/"&gt;ExtJS Extender Controls&lt;/a&gt;) tentava me explicar como tentar fazer um advogado entender a diferença entre as tecnologias &lt;b&gt;ASP&lt;/b&gt; (Asp 3 ou Asp "clássico") e &lt;b&gt;Asp.Net&lt;/b&gt;. O advogado em questão era um outro funcionário que validava uma feature do sistema jurídico.&lt;br /&gt;&lt;br /&gt;Conta o Diniz que argumentou o seguinte:&lt;br /&gt;&lt;blockquote&gt;&lt;i style="background-color: white;"&gt;Escrever em Asp é como escrever em Latim, enquanto Asp.Net é como escrever em Portugês. Dá para dizer a mesma coisa, mas um é mais antigo, menos preciso e já não há tanta gente que consegue entender.&lt;/i&gt;&lt;/blockquote&gt;&lt;br /&gt;Exageros a parte, até concordei com a idéia.&lt;br /&gt;E você, o que achou?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-4707686070108286783?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/4707686070108286783/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2011/07/asp-x-aspnet-como-explicar-para-leigos.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/4707686070108286783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/4707686070108286783'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2011/07/asp-x-aspnet-como-explicar-para-leigos.html' title='ASP x Asp.Net -- como explicar para leigos'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-4947272149185543235</id><published>2011-03-27T12:59:00.000-03:00</published><updated>2011-03-27T12:59:50.181-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='livemeeting'/><category scheme='http://www.blogger.com/atom/ns#' term='ubuntu'/><title type='text'>LiveMeeting no Ubuntu</title><content type='html'>Aconteceu ontem o MVC Summit 2011, desta vez totalmente web, transmitido através do LiveMeeting.&lt;br /&gt;&lt;br /&gt;Mesmo tendo a plataforma da Microsoft como a minha principal (C# Asp.Net), meu desktop roda Linux Ubuntu e, claro, não há um cliente nativo do LiveMeeting para o Ubuntu. Restou então a versão webhosted do client, que é baseado em Java.&lt;br /&gt;&lt;br /&gt;Claro que não ia ser simples assim, afinal a Canonical resolveu trocar o Java da Sun (agora Oracle), pelo Open Java, com o argumento que é a mesma coisa, só que OpenSource. Vá lá, ele até é bem bonzinho sim, mas o webclient do LiveMeeting não quis rodar com ele de jeito nenhum.&lt;br /&gt;&lt;br /&gt;Desconfiei que fosse esse o problema, e resolvi trocar a OpenJRE pela da Sun mesmo. Uma rápida "Googlada", e encontrei como substituir um pelo outro. Se alguém tiver dificuldade de achar, comenta aí, que eu passo o caminho das pedras.&lt;br /&gt;&lt;br /&gt;OpenJRE removido, Sun JRE instalado, vamos aos testes. A Microsoft tem disponível uma &lt;a href="https://www111.livemeeting.com/cc/test2007/webJoin?id=LiveMeeting2007Test&amp;pw=&amp;role=attend&amp;cn=user"&gt;página de testes de reuniões LiveMeeting&lt;/a&gt;. Infelizmente essa reunião de testes não tem áudio configurado, mas pelo menos serve para testar o vídeo. Só que mesmo com o JRE da Sun, o troço ainda não funcionava.&lt;br /&gt;&lt;br /&gt;Mais uma procurada, dessa vez bem demorada, e acabei encontrando um blog que divulgava uma dica de um brasileiro, que ensinava como acertar. O link que eu achei foi &lt;a href="http://www.proppedup.org/2011/01/26/live-meeting-on-ubuntu-lucid/"&gt;este aqui&lt;/a&gt;, o crédito original é do @CiroRodrigues e o resumo da história é esse:&lt;br /&gt;&lt;br /&gt;Vá no menu System &gt; Preferences &gt; Sun Java 6 Plugin Control Panel.&lt;br /&gt;Vá na &lt;i&gt;aba&lt;/i&gt; "Advanced", abra o item "Security", abra "Mixed Code (sandboxed vs. trusted) security verification", e selecione a opção "Enable - hide warning and run with protections".&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-nKgSxxqDOe4/TY9eCvqZ6wI/AAAAAAAAAEc/98aGHfxoAkc/s1600/java-control-panel.png" imageanchor="1" style=""&gt;&lt;img border="0" height="200" width="172" src="http://1.bp.blogspot.com/-nKgSxxqDOe4/TY9eCvqZ6wI/AAAAAAAAAEc/98aGHfxoAkc/s200/java-control-panel.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;É isso aí, espero que ajude.&lt;br /&gt;&lt;br /&gt;Abraços e até a próxima.&lt;br /&gt;@leozacche&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-4947272149185543235?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/4947272149185543235/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2011/03/livemeeting-no-ubuntu.html#comment-form' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/4947272149185543235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/4947272149185543235'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2011/03/livemeeting-no-ubuntu.html' title='LiveMeeting no Ubuntu'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-nKgSxxqDOe4/TY9eCvqZ6wI/AAAAAAAAAEc/98aGHfxoAkc/s72-c/java-control-panel.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-8850211228265765053</id><published>2010-09-23T10:20:00.000-03:00</published><updated>2010-09-23T10:20:03.279-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ps3'/><category scheme='http://www.blogger.com/atom/ns#' term='sony'/><category scheme='http://www.blogger.com/atom/ns#' term='social'/><category scheme='http://www.blogger.com/atom/ns#' term='teletransporte'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Teletransporte</title><content type='html'>Quem nunca desejou ter a sua própria máquina de tele-transporte, que atire a primeira pedra. Eu sempre quis ter uma, mesmo antes de assistir ao filme &lt;a href="http://www.youtube.com/watch?v=KqcgBJlLsg8"&gt;"A Mosca" (aquele com o Jeff Goldblum)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;É, meu caro, parece que não estamos sozinhos. A Sony, através do &lt;a href="http://us.playstation.com/psn/playstation-home/"&gt;PlayStation Home&lt;/a&gt;, realizou o nosso sonho. Virtualmente, pelo menos.&lt;br /&gt;&lt;br /&gt;Agora é só torcer para não haver colisão de pacotes, congestionamento de tráfego, nem faltar luz no meio do caminho. &lt;a href="http://www.viddler.com/explore/sceablog/videos/1261/3.2"&gt;Veja o trailer&lt;/a&gt; e me diga o que achou.&lt;br /&gt;&lt;br /&gt;abs&lt;br /&gt;&lt;br /&gt;LZ&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-8850211228265765053?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/8850211228265765053/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2010/09/teletransporte.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/8850211228265765053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/8850211228265765053'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2010/09/teletransporte.html' title='Teletransporte'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-3910990895511950589</id><published>2010-08-26T18:48:00.011-03:00</published><updated>2010-08-26T19:04:20.075-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='aspas duplas'/><category scheme='http://www.blogger.com/atom/ns#' term='aspas simples'/><category scheme='http://www.blogger.com/atom/ns#' term='apostrofo'/><category scheme='http://www.blogger.com/atom/ns#' term='aspas'/><category scheme='http://www.blogger.com/atom/ns#' term='sql dinamico'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Dicas para SQL Dinâmico - Apóstrofos</title><content type='html'>&lt;p&gt;Olá pessoal.&lt;br/&gt;&lt;br /&gt;A dica de hoje vai para quem precisa construir comandos SQL dinâmicos, seja dentro de stored procedures ou diretamente no código da sua linguagem de preferência. Vou usar Oracle para o exemplos, mas o conceito também se aplica ao SQL Server. Para deixar os posts menores, vou fazer cada dica um post diferente.&lt;/p&gt;&lt;br /&gt;&lt;b&gt;Apóstrofo (ou aspas simples)&lt;/b&gt;&lt;br /&gt;&lt;p&gt;Todo mundo sabe que, em uma instrução SQL, as strings são delimitadas por apóstrofo (que alguns chamam de aspas simples). Assim:&lt;br /&gt;&lt;/p&gt;&lt;div class="sourceCode"&gt;create table tab_a (col1 varchar2(100) not null, col2 varchar2(100) not null);&lt;br /&gt;declare&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minha_string varchar2(1000);&lt;br /&gt;begin&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;minha_string := 'isso é uma string';&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Muito bem. Mas e se a string em questão for uma instrução SQL? Ela, por natureza é uma linha de texto e que pode ter uma string dentro. Imagine o comando:&lt;/p&gt;&lt;div class="sourceCode"&gt;insert into tab_A (col1, col2) values ('valor 1', 'valor 2');&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Se esse comando for uma instrução SQL dinâmica, você teria algo como isso:&lt;/p&gt;&lt;div class="sourceCode"&gt;declare&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meu_sql varchar2(1000);&lt;br /&gt;begin&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;meu_sql := 'insert into tab_A (col1, col2) values (''valor 1'', ''valor 2'')';&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Repare que para reproduzir um apóstro dentro de uma string, eu tenho que duplicá-lo, porque ele é um caracter especial (delimitador de string). Se colocasse sem duplicar, o compilador ia acusar erro, achando que haveria strings em sequencia, sem concatenar, nem nada. &lt;br /&gt;&lt;br /&gt;Agora vamos adicionar um pouco de complexidade ao exemplo. Vou transformar esse pequeno bloco anônimo numa stored procedure com dois parâmetros do tipo string, que serão usados para preencher col1 e col2.&lt;/p&gt;&lt;div class="sourceCode"&gt;create or replace procedure proc_exemplo (pCol1 in varchar2, pCol2 in varchar2) as&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vSQL varchar2(1000);&lt;br /&gt;begin&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vSQL := 'insert into tab_A (col1, col2) values (''' || pCol1 || ''', ''' || pCol2 || ''')';&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execute immediate vSQL;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;i&gt;Sabemos que usar variáveis de ligação é muito mais eficiente, mas resolvi adotar esta estratéria &lt;br /&gt;"ruim" apenas como exemplo de manipulação de strings. Outro dia eu falo sobre &lt;u&gt;binding vars&lt;/u&gt;.&lt;/i&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Repare como os diversos apóstrofos colados começam a prejudicar a leitura do código da proc. E é apenas uma linha de código!!! Imagine um insert imenso com muitas colunas string, o comando quebrado em várias linhas... Começa a ficar realmente ruim.&lt;br/&gt;&lt;br /&gt;Para deixar o código mais limpo (facilitar a leitura), eu vou substituir cada apóstrofo duplicado (aqueles de dentro da string, e somente esses!) por uma aspa comum (ou dupla, se preferir). Percebe que um apóstrofo duplicado ('') não é a mesma coisa que uma aspa ("). São caracteres diferentes!!!.&lt;/p&gt;&lt;div class="sourceCode"&gt;create or replace procedure proc_exemplo (pCol1 in varchar2, pCol2 in varchar2) as&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vSQL varchar2(1000);&lt;br /&gt;begin&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vSQL := 'insert into tab_A (col1, col2) values ("' || pCol1 || '", "' || pCol2 || '")';&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execute immediate vSQL;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/div&gt;&lt;p&gt;Mais fácil de ler, não?&lt;br/&gt;Mais fácil para identificar onde começa e onde termina cada string (cada "pedaço" do comando SQL).&lt;br/&gt;&lt;br/&gt;Só que se você executar esta proc, vai dar erro. Isto porque as aspas não são aceitas (em PL/SQL nem T-SQL) como delimitadores de string.&lt;/br&gt;&lt;br/&gt;&lt;br /&gt;A correção é bem simples: Pode usar aspas à vontade dentro da sua string e, no último momento antes de executar o comando, você converte todas as aspas para apóstrofos duplos.&lt;/p&gt;&lt;div class="sourceCode"&gt;create or replace procedure proc_exemplo (pCol1 in varchar2, pCol2 in varchar2) as&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vSQL varchar2(1000);&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- preparando o comando SQL&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vSQL := 'insert into tab_A (col1, col2) values ("' || pCol1 || '", "' || pCol2 || '")';&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-- fazendo os ultimos ajustes antes de executar&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;vSQL := replace(vSQL, '"', '''');&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;execute immediate vSQL;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;&lt;/div&gt;&lt;p&gt;A linha do replace é a única que você terá que manter bagunçada (vários caracteres apóstrofo), mas como é uma linha só, que fica só no final do bloco de código, dá para conviver.&lt;br/&gt;&lt;br/&gt;Há uma restrição que você não pode usar aspas para nenhum outro fim, dentro do seu comando SQL. Se você puder atender este requisito, está feito. E eu particularmente não considero uma coisa muito esperta usar aspas (") nos nomes dos objetos Oracle. Serve só para dar dor-de-cabeça, mas isso também é papo para outro dia.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;É isso pessoal.&lt;br/&gt;Espero que sirva de ajuda para alguém por aí.&lt;br/&gt;&lt;br/&gt;&lt;br/&gt;Abraços,&lt;br/&gt;&lt;br /&gt;LZ&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-3910990895511950589?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/3910990895511950589/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2010/08/dicas-para-sql-dinamico-apostrofos.html#comment-form' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/3910990895511950589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/3910990895511950589'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2010/08/dicas-para-sql-dinamico-apostrofos.html' title='Dicas para SQL Dinâmico - Apóstrofos'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-51109570077765670</id><published>2010-08-19T14:54:00.015-03:00</published><updated>2010-08-19T18:20:12.930-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debug'/><category scheme='http://www.blogger.com/atom/ns#' term='stored procedure'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>Parâmetro opcional em stored procedure (mão na roda)</title><content type='html'>&lt;div&gt;&lt;br /&gt;    &lt;div&gt;Hoje vou dar uma dica para facilitar o trabalho de debug de uma stored procedure. Vai em Oracle, porque é o que eu tenho na mão para mostrar (sem falar da minha preferência, claro).&lt;br /&gt;&lt;br /&gt;        Frequentemente, quando escrevo uma nova stored procedure (ou altero uma existente), eu acrecento um parâmetro adicional, opcional, que indica se a proc deve rodar em "modo debug". Coloco no final da lista de parâmetros (geralmente é o último) e como opcional, porque assim eu não preciso alterar nenhum programa que use esta proc, e ainda tenho a flexibilidade de usar o parâmetro.&lt;br /&gt;&lt;br /&gt;        "Mas o que faz este parâmetro?" - perguntarão alguns. Eu já disse! Indica se a proc deve rodar em modo debug.&lt;br /&gt;&lt;br /&gt;        "Modo debug?"&lt;br /&gt;&lt;br /&gt;        É. É um apelido, uma forma sofisticada de dizer que a proc vai fazer algum trabalho extra. No caso, o trabalho de coletar informações sobre a sua própria execução.&lt;br /&gt;        Essa coleta pode ser, exibir o valor de uma variável, indicar se entrou em um IF (ou se entrou no ELSE), exibir a quantide de registros lidos, etc...&lt;br /&gt;&lt;br /&gt;        Vamos ao exemplo prático:&lt;br /&gt;&lt;br /&gt;        (lembrando, é ORACLE e vc pode colar os comandos direto no SQL*Plus)&lt;br /&gt;&lt;br /&gt;        Imagine uma proc spProc1, que serve apenas para inserir descrições em uma tabela TabA, se não existirem, e retornar o Id gerado. Assim:&lt;/div&gt;&lt;br /&gt;    &lt;div class="sourceCode"&gt;create table TabA (&lt;br /&gt;    Id             number        not null,&lt;br /&gt;    Descricao      varchar2(50)  not null,&lt;br /&gt;    DataCriacao    date          not null&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;alter table TabA add constraint PK_TabA primary key (Id);&lt;br /&gt;alter table TabA add constraint UK_TabA_Descricao unique (Descricao);&lt;br /&gt;&lt;br /&gt;create or replace procedure spProc1(pDescricao in varchar2, pId out number) as&lt;br /&gt;    vQtd number;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    select count(1) into vQtd from TabA where Descricao = pDescricao;&lt;br /&gt;&lt;br /&gt;    if (vQtd = 0) then&lt;br /&gt;&lt;br /&gt;        select nvl(max(Id),0)+1 into pId from TabA;&lt;br /&gt;&lt;br /&gt;        insert into TabA (Id, Descricao, DataCriacao)&lt;br /&gt;        values (pId, pDescricao, sysdate);&lt;br /&gt;&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Vamos inserir uns dados para ver que está tudo funcionando direito...&lt;/div&gt;&lt;br /&gt;    &lt;div class="sourceCode"&gt;variable novo_id number&lt;br /&gt;&lt;br /&gt;exec spProc1('Leonardo', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('ImaginarTI', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Zacche', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;select * from TabA;&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Agora vamos supor que você descobriu que, se ao chamar a proc, fornecer uma descrição que já exista na tabela, o ID retornado é nulo.&lt;/div&gt;&lt;br /&gt;    &lt;div class="sourceCode"&gt;exec spProc1('Mais um', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Mais um', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Depurar esta procedure é fácil porque é curta. Uma procedure longa, seria mais complicado. Para facilitar, vou colocar algumas linhas de DEBUG na procedure.&lt;/div&gt;&lt;br /&gt;    &lt;div class="sourceCode"&gt;create or replace procedure spProc1(pDescricao in varchar2, pId out number) as&lt;br /&gt;    vQtd number;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    select count(1) into vQtd from TabA where Descricao = pDescricao;&lt;br /&gt;    dbms_output.put_line(vQtd || ' registro(s) encontrado(s).');&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if (vQtd = 0) then&lt;br /&gt;&lt;br /&gt;        select nvl(max(Id),0)+1 into pId from TabA;&lt;br /&gt;        dbms_output.put_line('O Id gerado foi ' || pID);&lt;br /&gt;&lt;br /&gt;        insert into TabA (Id, Descricao, DataCriacao)&lt;br /&gt;        values (pId, pDescricao, sysdate);&lt;br /&gt;&lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Vamos testar novamente, com um novo valor, e depois repetí-lo.&lt;/div&gt;&lt;br /&gt;&lt;div class="sourceCode"&gt;set serveroutput on 100000&lt;br /&gt;exec spProc1('Teste dois', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste dois', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Descobrimos que não está entrando no IF. Vamos escrever um ELSE.&lt;/div&gt;&lt;br /&gt;    &lt;div class="sourceCode"&gt;create or replace procedure spProc1(pDescricao in varchar2, pId out number) as&lt;br /&gt;    vQtd number;&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    select count(1) into vQtd from TabA where Descricao = pDescricao;&lt;br /&gt;    dbms_output.put_line(vQtd || ' registro(s) encontrado(s).');&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if (vQtd = 0) then&lt;br /&gt;&lt;br /&gt;        select nvl(max(Id),0)+1 into pId from TabA;&lt;br /&gt;        dbms_output.put_line('O Id gerado foi ' || pID);&lt;br /&gt;&lt;br /&gt;        insert into TabA (Id, Descricao, DataCriacao)&lt;br /&gt;        values (pId, pDescricao, sysdate);&lt;br /&gt;&lt;br /&gt;    else&lt;br /&gt;&lt;br /&gt;        select Id into pId from TabA where Descricao = pDescricao;&lt;br /&gt;        dbms_output.put_line('O Id encontrado foi ' || pID);&lt;br /&gt;        &lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste tres', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste tres', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Agora a proc já está funcionando da forma que desejamos! Um último refactoring para otimizar o código e ...&lt;/div&gt;&lt;br /&gt;    &lt;div class="sourceCode"&gt;create or replace procedure spProc1(pDescricao in varchar2, pId out number) as&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    begin&lt;br /&gt;        select Id into pId from TabA where Descricao = pDescricao;&lt;br /&gt;        dbms_output.put_line('O Id encontrado foi ' || nvl(to_char(pID),'[nulo]'));&lt;br /&gt;    exception&lt;br /&gt;        when NO_DATA_FOUND then pId := null;&lt;br /&gt;        when OTHERS then raise;&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if (pId is null) then&lt;br /&gt;&lt;br /&gt;        select nvl(max(Id),0)+1 into pId from TabA;&lt;br /&gt;        dbms_output.put_line('O Id gerado foi ' || pID);&lt;br /&gt;&lt;br /&gt;        insert into TabA (Id, Descricao, DataCriacao)&lt;br /&gt;        values (pId, pDescricao, sysdate);&lt;br /&gt;        &lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste quatro', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste quatro', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;    &lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Perfeito! A proc está exatamente como desejamos!&lt;br /&gt;&lt;br /&gt;        Agora podemos remover aquelas linhas de debug...&lt;br /&gt;&lt;br /&gt;        Mas seria interessante deixar essas linhas, para o caso de precisar depurar novamente...&lt;br /&gt;&lt;br /&gt;        Só que não é legal deixar essas linhas serem executadas SEMPRE, somente quando precisarmos&lt;br /&gt;        depurar.&lt;br /&gt;&lt;br /&gt;        Aí entra em cena o parâmetro opcional que comentei no início deste post. Como o parâmetro é OPCIONAL (todo parâmetro que tem um valor default pode ser otimido), você não precisa indicar o valor.&lt;br /&gt;&lt;br /&gt;        Assim, os programas que usam a proc não precisam ser alterados.&lt;br /&gt;&lt;br /&gt;        Eu defini o valor default como FALSE porque normalmente a proc não deve exibir informações de debug.&lt;br /&gt;&lt;br /&gt;        Nos casos (especiais) que eu quiser mostrar, informo explicitamente o valor true.&lt;/div&gt;&lt;br /&gt;    &lt;div class="sourceCode"&gt;create or replace procedure spProc1(pDescricao in varchar2, pId out number, p_showDebug in boolean default false) as&lt;br /&gt;begin&lt;br /&gt;&lt;br /&gt;    begin&lt;br /&gt;        select Id into pId from TabA where Descricao = pDescricao;&lt;br /&gt;        if (p_showDebug) then&lt;br /&gt;            dbms_output.put_line('O Id encontrado foi ' || nvl(to_char(pID),'[nulo]'));&lt;br /&gt;        end if;&lt;br /&gt;    exception&lt;br /&gt;        when NO_DATA_FOUND then pId := null;&lt;br /&gt;        when OTHERS then raise;&lt;br /&gt;    end;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    if (pId is null) then&lt;br /&gt;&lt;br /&gt;        select nvl(max(Id),0)+1 into pId from TabA;&lt;br /&gt;        if (p_showDebug) then&lt;br /&gt;            dbms_output.put_line('O Id gerado foi ' || pID);&lt;br /&gt;        end if;&lt;br /&gt;&lt;br /&gt;        insert into TabA (Id, Descricao, DataCriacao)&lt;br /&gt;        values (pId, pDescricao, sysdate);&lt;br /&gt;        &lt;br /&gt;    end if;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;/&lt;br /&gt;show errors&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste cinco', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste cinco', :novo_id);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste cinco', :novo_id, true);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;br /&gt;exec spProc1('Teste seis', :novo_id, true);&lt;br /&gt;print novo_id;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;    &lt;div&gt;Abraços e até a próxima!&lt;br/&gt;&lt;br /&gt;LZ&lt;br/&gt;&lt;br /&gt;&lt;a href="http://www.imaginarti.com" target="_blank"&gt;www.imaginarti.com&lt;/a&gt;&lt;br /&gt;    &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-51109570077765670?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/51109570077765670/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2010/08/parametro-opcional-em-stored-procedure.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/51109570077765670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/51109570077765670'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2010/08/parametro-opcional-em-stored-procedure.html' title='Parâmetro opcional em stored procedure (mão na roda)'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-174201956049160826</id><published>2010-05-29T22:09:00.010-03:00</published><updated>2010-05-30T02:28:11.967-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vmware player'/><category scheme='http://www.blogger.com/atom/ns#' term='virtualbox'/><category scheme='http://www.blogger.com/atom/ns#' term='virtual pc'/><category scheme='http://www.blogger.com/atom/ns#' term='hypervisor'/><title type='text'>Trielo de Hypervisors (Windows Guest)</title><content type='html'>E aí, pessoal? Faz tempo, né?&lt;div&gt;Hoje eu resolvi escrever sobre um assunto que eu tenho comentado e vivido bastante, ultimamente: Máquinas Virtuais (ou &lt;a href="http://en.wikipedia.org/wiki/Hypervisor"&gt;hypervisor&lt;/a&gt;s). E achei melhor fazer na forma de um trielo. Por que trielo?? Porque são três "competidores", se fossem dois seria um duelo.  :-)&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Eu testei o &lt;a href="http://www.microsoft.com/windows/virtual-pc"&gt;Microsoft Virtual PC&lt;/a&gt;, o &lt;a href="http://www.vmware.com/products/player"&gt;VMWare Player&lt;/a&gt; e o &lt;a href="http://www.oracle.com/us/technologies/virtualization/oraclevm/061976.html"&gt;Oracle VirtualBox&lt;/a&gt;. E como eu disse antes, foi uma comparação nada técnica. Eu não usei softwares de benchmarking, não medi tempos com ferramentas automáticas, muito menos carga de CPU, memória, etc. Tudo o que vou contar é simplesmente a minha impressão sobre os produtos. Se isso te ajuda, read on. Senão, sorry mate.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Eu instalei os três produtos no meu desktop. É um Athlon 64 3800+, 2Gb de RAM, HD interno 160Gb SATA, HD 500Gb SATA em um case USB, placa de vídeo NVidia GeForce 6200 com dois monitores (LG W1942S na VGA e Samsung P2470HN na DVI). As três VM foram instaladas no HD externo e os softwares para instalação também estavam neste HD externo.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A máquina física roda WinXP sp3 e tem só 2Gb. Para rodar três VMs com 512Mb cada uma, não sobrou quase nada o host OS, tadinho. A terceira VM a rodar (o VirtualPC) só subiu depois de parar vários serviços no host (entre eles SQL Server, terminal remoto, etc.). Depois de conseguir subir as 3 VM's, o host OS ficou insuportavelmente lento. Aliás, escrever este post não está sendo nada fácil...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Apesar de não ter nenhum critério técnico nesta comparação, procurei ser imparcial ao máximo. A tarefa consistia em instalar o sistema operacional (Windows XP Professional English sp2), instalar o Service Pack 3, instalar o &lt;i&gt;Guest OS Additions&lt;/i&gt; (específico de cada produto), instalar o AVG Free, instalar o Zone Alarm e desinstalar componentes desnecessários do Windows (wallpaper, ponteiros de mouse, games, etc.). As instalações foram executadas nas 3 VM's simultaneamente (descontando o tempo de mover o mouse para a outra VM e clicar no botão). Eu pretendia instalar o Visual Studio 2010 Express, mas já gastei muito tempo e o VS vai ficar para outro dia.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;E depois de algumas horas executando essas tarefas, eis as minhas impressões:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Preço&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;Todos os três são grátis. :-)&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Contato Inicial&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;O VirtualPC parece ser mais fácil de operar. Talvez por ser obviamente mais simples (menos opções, menos funcionalidades), talvez por ter mais a cara (look 'n feel) do Windows, é o que oferece maior conforto para um usuário iniciante.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O VirtualPC também tem o esquema mais simples de &lt;i&gt;Shared Folder&lt;/i&gt; (uma pasta no host que é compartilhada no guest como um drive mapeado ou um network share, para facilitar troca de arquivos entre o host e o guest).&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Performance&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;O VirtualBox é disparado o mais performático. Iniciei algumas tarefas primeiro no VirtualPC, outras iniciei primeiro no VirtualBox e outras iniciei primeiro no VMWare Player. Em absolutamente todos os casos o VirtualBox terminou primeiro. É razoavelmente mais rápido que o VirtualPC e muito mais rápido que o VMWare Player. A diferença é absurda (usei sempre as configurações default). Na hora de instalar o SP3 do Windows foi o ápice: iniciei a instalação no VMWare Player. 5 minutos depois, comecei no VirtualPC. Passados mais 5 minutos, iniciei no VirtualBox. Quase uma hora depois, o VirtualBox terminou antes dos demais e ficou parado esperando os outros. Em seguida veio o VirtualPC e muito tempo depois o VMWare Player cruzou a linha de chegada, se rastejando. Aliás, depois de um tempo com o Windows paradinho, sem fazer nada, o VMWare Player continua acessando HD, CD e rede sem parar, enquanto os outros só acessam (muito) de vez em quando.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Usabilidade&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;/b&gt;Neste ponto eu considero um empate técnico com ligeira vitória para o VirtualBox. Todos os três produtos são bem similares, as diferenças são bem sutis. O VirtualPC tem o esquema mais simples para usar um arquivo .ISO como um drive de CD. Ponto para ele porque é realmente simples e rápido. Os outros são bem mais flexíveis, permitem ter uma biblioteca de .ISO's pré-configurada, o que permite alternar rapidamente entre as imagens ISO. Mesmo assim prefiro a facilidade do VirtualPC.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Outro ponto que achei interessante (e dessa vez ponto para o VirtualBox) é a integração com o ponteiro do mouse. Achei fantástico.  Enquanto no VirtualPC e no VMWare você tem que clicar uma vez para ativar a janela (se ela não estiver ativa) e outra vez para acionar o controle (clicar em um botão, um checkbox, etc.). Já no VirtualBox o mesmo clique aciona a janela (se for necessário) e aciona o controle, tudo de uma vez só. Isso deixa a experiência do usuário particularmente confortável quando há necessidade de muitas interações dentro e fora da VM, como quando eu estava desinstalando componentes desnecessários do Windows. Nessa hora eu precisei marcar e desmarcar vários checkboxes simultaneamente nas 3 VM's.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;b&gt;Flexibilidade&lt;/b&gt;&lt;br /&gt;Nesta questão, o VMWare é melhor do que o VirtualBox... e dá couro no VirtualPC. No VirtualPC há uma tecla fixa para liberar o ponteiro do mouse (quendo foi capturado pelo guest OS e a integração de ponteiro não está instalada). No VirtualBox e no VMWare esta tecla pode ser configurada (e é bem fácil de fazer).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As bibliotecas de imagens .ISO's que existem no VirtualBox e no VMWare são um conceito interessante. Facilitam na troca de mídia no CD "virtual", o que é ótimo se você precisa instalar várias VM's com a mesma mídia... Ou se precisa ficar alternando mídias (bota um disco, bota outro disco, bota um disco, bota outro disco, ...). O mesmo não dá para fazer com o VirtualPC. E se as mídias .ISO estiverem em pastas diferentes, a tarefa fica bem tediosa.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O VirtualBox e o VMWare reconheceram de cara os dispositivos USB ligados no host (o HD externo e o leitor de cartões, que apesar de interno, é USB). Reconheceram até a marca (JMicro) e modelo (JM20336) do case que contém o HD (o HD externo é esse case + HD de notebook). Ambos os softwares ofereceram menus para ligar os dispositivos USB (e acessá-los diretamente). Além dessa opção no menu, também há essa opção através de ícones na barra de ferramentas na parte inferior da janela da VM (um atalho). O VMWare chegou a me oferecer isso através de uma janela (com botões "sim" e "não"). O VirtualPC passou longe de saber que há algum USB espetado, embora afirme que é possível conectar as COM e a LPT do host. Eu não usei essas opções, mas achei interessante a possibilidade.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Outros aspectos&lt;/b&gt;&lt;br /&gt;O reconhecimento da placa de som é bem transparente nos três produtos e mapeamento da placa virtual para a física ocorreu sem problemas.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O hardware virtual disponibilizado pelo VMWare reportou suportar &lt;a href="http://en.wikipedia.org/wiki/Physical_Address_Extension"&gt;PAE (Physical Address Extension)&lt;/a&gt;. Os outros produtos não reportaram PAE.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Quando se cria uma VM com o VMWare, ele te pergunta se você quer criar o HD virtual como um arquivo único ou se quer dividir em arquivos de (no máximo 2Gb). É ótimo ter a opção de escolher (principalmente se você precisar copiar o HD virtual entre computadores diferentes), mas a maneira do VirtualPC (arquivo único) é bem mais simples. O VMWare tem um monte de arquivos, dá a impressão de ser meio confuso. O VirtualBox criar os HDs virtuais como arquivos únicos e permite compartilhar um mesmo HD Virtual entre várias VM's. Flexibilidade total e um recurso interessante, mas é um conteito muito estranho para quem nunca tinha ouvido falar, que era o meu caso. Levei um tempinho até entender como a coisa funciona.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O VMWare tem um recurso muito interessante para auxiliar na instalação de um sistema operacional. Ele é tão esperto que pode interagir com o programa de instalação e fornecer informações (previamente fornecidas por você ou baseadas no default do programa) de forma que a instalação pode acontecer de forma não assistida. Por isso, instalar o Windows XP no VMWare é muito mais rápido que qualquer outro: enquanto os concorrentes ficam esperando você informar a CD-KEY ou clicar em "configurações padrão" (na instalação da rede), o VMWare se vira sozinho e não fica esperando por você. Resultado: menor tempo de instalação, menos tempo que você "perde".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Há um recurso no VirtualBox e no VMWare (novamente o VirtualPC ficou de fora) que deixa o uso bem interessante: é a possibilidade de executar uma determinada aplicação sem exibir o desktop virtual (a janela da aplicação rodando no guest é exibida diretamente no host). Assim, dá a impressão que a aplicação está rodando no host (já que só a aplicação é visível e deixa de estar restrita ao tamanho do desktop do guest), mas na verdade ainda é uma máquina virtual. Esse recurso é chamado de &lt;b&gt;unity&lt;/b&gt; no VMWare e &lt;b&gt;modo seamless&lt;/b&gt; no VirtualBox. Vale a pena experimentar.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Com relação ao consumo de memória do host, o VirtualBox passa a impressão de ir obtendo memória à medida que o guest for precisando. O VirtualPC e o VMWare, ao contrário, reservam a quantidade de RAM que a VM precisa, logo que a VM é iniciada. Sem ferramentas fica difícil comprovar essa teoria (também não achei nada a esse respeito na documentação), mas é fácil acompanhar a quantidade de memória em uso pelo processo, usando o Gerenciador de Tarefas do Windows host. A medida que a VM vai iniciando processos, esta VM vai aumentando o consumo de memória no host. Já no VirtualPC e no VMWare, o consumo de memória é fixo. Isso é um aspecto muito interessante porque, dependendo do que a VM for executar e da quantidade de memória disponível no host, o uso do VirtualBox pode não deixar o host tão lento.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rodar três VM's no mesmo HD externo... Dá para fritar um ovo no chassi do HD externo.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Conclusão&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Diante de todos os aspectos que eu experimentei, eu penso que o VirtualPC é muito básico. Serve apenas se você tem muito pouca necessidade de rodar uma máquina virtual e se ela for Windows. Por exemplo: se você precisa executar uma versão anterior do IE, ou uma tarefa básica assim, VirtualPC 2007 te cai bem.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O VMWare Player é um produto bastante robusto e acho que ele serve bem se você precisa usar uma VM para fins profissionais (mesmo com o apetite por I/O). Com esta versão free, você pode ter várias VM's, mas só pode rodar uma de cada vez. Tem excelente suporte a hardware e se você tem uma CPU com suporte a virtualização assistida por hardware.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;O Oracle VirtualBox é outra excelente opção, principalmente se você rodar mais de uma VM por vez. É o produto que eu mais gostei pela perfeita integração com o ponteiro do mouse, pelo consumo moderado de memória do host, pela possibilidade de rodar mais de uma VM. O que ele eventualmente perde para o VMWare Player não chega a fazer falta. É por isso que vou ficar com este produto.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Vejam uma foto do meu desktop com as três VM's rodando ao mesmo tempo.&lt;/div&gt;&lt;img src="http://lh5.ggpht.com/_OVa5hAqn324/TAHwdiuNyOI/AAAAAAAAADY/x6AyXrGqTZM/tres_vms.jpg" /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Vale ressaltar que eu não testei Microsoft Virtual Server, nem o Virtual PC para Windows Seven (e o famoso XP Mode), nem o Oracle VM Server, nem o VMWare Workstation (nem irmãos "maiores"). Também não testei XEN e outros produtos famosos do mercado. Testei apenas os que eu tinha à mão e que são alguns dos mais comuns.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Espero que minhas impressões possam ajudar alguém por aí.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Forte abraço e até a próxima.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-174201956049160826?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/174201956049160826/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2010/05/trielo-de-hypervisors-windows-guest.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/174201956049160826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/174201956049160826'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2010/05/trielo-de-hypervisors-windows-guest.html' title='Trielo de Hypervisors (Windows Guest)'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_OVa5hAqn324/TAHwdiuNyOI/AAAAAAAAADY/x6AyXrGqTZM/s72-c/tres_vms.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-6623690649147805374</id><published>2009-09-17T02:56:00.004-03:00</published><updated>2009-09-17T03:19:59.324-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='temporary table'/><category scheme='http://www.blogger.com/atom/ns#' term='on the fly'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='temp table'/><category scheme='http://www.blogger.com/atom/ns#' term='tabela temporaria'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>SQL Server - E porque eu gosto mais do Oracle (temporary table)</title><content type='html'>De volta ao duelo SQL Server x Oracle.&lt;br /&gt;&lt;br /&gt;Como hoje eu estava comentando com um amigo no trabalho sobre as tabelas temporárias, resolvi aproveitar e escrever sobre o assunto.&lt;br /&gt;&lt;br /&gt;Rápido esclarecimento (se há alguém que ainda não sabe!): uma tabela temporária é aquela que cujos dados estão "visíveis" somente à sua sessão e, depois de usados são descartados (não são gravados em disco).&lt;br /&gt;&lt;br /&gt;Pela ANSI há dois tipos de tabelas temporárias: as locais e as globais.&lt;br /&gt;&lt;br /&gt;As &lt;span style="font-weight: bold;"&gt;LOCAIS &lt;/span&gt;são criadas no momento em que são necessárias (ou seja, "&lt;span style="font-style: italic; font-weight: bold;"&gt;on the fly&lt;/span&gt;"), não estão presentes no catálogo do banco, são usadas e, quando não são mais necessárias são destruídas.&lt;br /&gt;&lt;br /&gt;As &lt;span style="font-weight: bold;"&gt;GLOBAIS &lt;/span&gt;são criadas previamente ao uso, fazem parte do catálogo e, quando não são mais necessárias, apenas os dados são descartados.&lt;br /&gt;&lt;br /&gt;Em linhas gerais, o SQL Server trabalha somente com temporárias locais, enquanto o Oracle trabalha somente com temporárias globais.&lt;br /&gt;&lt;br /&gt;E porque eu prefiro as globais?&lt;br /&gt;&lt;br /&gt;1) Porque fazem parte do catálogo. Assim eu posso escrever várias stored procedures que usam a mesma temp table, sem preocupações. Inclusive os planos de acesso são previamente compilados. Posso estabelecer foreign keys.  Ou seja, garantem a integridade dos dados com menos trabalho.&lt;br /&gt;&lt;br /&gt;2) DDL é "caro". Os comandos do tipo DDL (data definition language) consomem muito tempo de CPU (tempo de "preparação", ou seja, interpretação, compilação, etc., não tempo de execução) se comparados com os DML (data modification language). E quando o programa / sistema / software está rodando, você quer que rode o mais rápido possível. Não "perder tempo" criando e destruindo objetos é um recurso valioso.&lt;br /&gt;&lt;br /&gt;3) No Oracle eu posso definir em que momento os dados serão desprezados, se no &lt;span style="font-style: italic;"&gt;commit &lt;/span&gt;ou se no &lt;span style="font-style: italic;"&gt;disconnect&lt;/span&gt;. Isso é feito de forma declarativa, na criação da tabela, e me dá mais flexibilidade do que o SQL Server, que só oferece uma forma automática de desprezar os dados (no disconnect, quando a tabela é destruída).&lt;br /&gt;&lt;br /&gt;O primeiro argumento é definitivamente o mais forte, pois trás à reboque outros argumentos (por existir no catálogo eu posso isso, eu posso aquilo, etc.).&lt;br /&gt;&lt;br /&gt;Concordam? Discordam? Dêem suas opiniões!&lt;br /&gt;&lt;br /&gt;Até a próxima!&lt;br /&gt;&lt;img src="http://www.imaginarti.com/Blogs/LeoZacche.png" alt="Leo Zacche" border="0" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-6623690649147805374?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/6623690649147805374/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2009/09/sql-server-e-porque-eu-gosto-mais-do.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/6623690649147805374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/6623690649147805374'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2009/09/sql-server-e-porque-eu-gosto-mais-do.html' title='SQL Server - E porque eu gosto mais do Oracle (temporary table)'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-1378139209692914143</id><published>2009-07-26T18:55:00.013-03:00</published><updated>2009-07-26T20:02:32.438-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='anti-spam'/><category scheme='http://www.blogger.com/atom/ns#' term='catch-all'/><title type='text'>A luta contra o SPAM</title><content type='html'>Como a empresa é bem pequena (somos equipe, digamos... reduzida!), eu acumulo tarefas. Uma delas é ser o administrador do correio eletrônico. E hoje vou comentar sobre o saco que é lutar contra o SPAM.&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" border="0" alt="" src="http://lh3.ggpht.com/_OVa5hAqn324/SmzZNlLk_FI/AAAAAAAAACY/OMqubC7ssks/s144/spam.jpg" /&gt;&lt;br /&gt;Como toda microempresa que se preza, eu não posso me dar ao luxo de perder um email enviado a nós... pois ali pode ter uma oportunidade interessante. Penso que algumas empresas maiores se permitam monitorar somente as caixas postais formalmente publicadas no seu site... Como não é o caso, eu configurei uma conta para ser Catch-All.&lt;br /&gt;&lt;br /&gt;Como essa Cacth-All (eu detesto o termo em Português: "Pega-Tudo". Argh!) recebe mensagens que foram enviadas a caixas postais que não existem, é ali que se acumula o spam. E que saco é lutar contra o maldito spam.&lt;br /&gt;&lt;br /&gt;Como o volume de spam é bem alto, você logo começa a catar ferramentas para eliminar essa praga. Usamos o SmarterMail Enterprise, que tem umas ferramentas anti-spam que até ajudam, mas não fazem tudo. Então eu comecei a analizar o maldito spam que chegava.&lt;br /&gt;&lt;br /&gt;Obervando o cabeçalho das mensagens percebi que a maioria (eu chutaria uns 70%) chega no meu servidor diretamente de uma máquina que parece ter IP dinâmico... um usuário de banda larga. Obviamente infectado com algum vírus, que se aproveita da banda do incauto. Como esse exemplo:&lt;br /&gt;&lt;br /&gt;&lt;div class="sourceCode"&gt;Received: from client-82-12-232-213.brnt.adsl.virgin.net [82.12.232.213] by meu.servidor.de.email with SMTP;&lt;/div&gt;&lt;br /&gt;Isso é uma das linhas de cabeçalho de uma das mensagens indesejadas. Ela diz que a mensagem foi recebida pelo meu servidor de mail (mudei o nome de propósito), através de uma conexão SMTP (o protocolo de envio de emails) que foi iniciada pelo computador client....virgin.net. Nem me dei ao trabalho de checar, mas sou capaz de apostar como Virgin.Net é o domínio de algum provedor de banda larga. Repare no no IP (entre colchetes), que é repetido no nome do computador (que é dado pelo DHCP). Repare também no ".adsl.". Bingo. Usuário de banda larga infectado.&lt;br /&gt;&lt;br /&gt;Ok, mas o que eu faço com isso??&lt;br /&gt;Uso uma outra ferramenta do meu servidor de email, que é o filtro de conteúdo. Criei uma regra que apaga automaticamente todas as mensagens que tenham no cabeçalho, a linha acima, só que com uma pequena modificação: usando wildcards (que o servidor "entende"). Fica assim:&lt;br /&gt;&lt;br /&gt;&lt;div class="sourceCode"&gt;Received: from client-*.brnt.adsl.virgin.net [*] by meu.servidor.de.email with SMTP;&lt;/div&gt;&lt;br /&gt;Ou seja, agora minha regra é: apagar todas as mensagens que sejam recebidas pelo meu servidor, enviadas diretamente de qualquer usuário de banda larga dessa tal de virgin.net.&lt;br /&gt;&lt;br /&gt;Uma ou duas vezes por semana, preciso acrescentar entradas novas nesta regra, mas o volume de spam cai muito. Mostrou-se ser uma boa prática.&lt;br /&gt;&lt;br /&gt;Espero que a dica ajuda mais alguém por aí.&lt;br /&gt;&lt;br /&gt;Abraços e até a próxima!&lt;br /&gt;&lt;br /&gt;&lt;img src="http://www.imaginarti.com/Blogs/LeoZacche.png" border="0" alt="Leo Zacche" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-1378139209692914143?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/1378139209692914143/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2009/07/luta-contra-o-spam.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/1378139209692914143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/1378139209692914143'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2009/07/luta-contra-o-spam.html' title='A luta contra o SPAM'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_OVa5hAqn324/SmzZNlLk_FI/AAAAAAAAACY/OMqubC7ssks/s72-c/spam.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-2206806468237876785</id><published>2009-06-07T17:40:00.008-03:00</published><updated>2009-06-07T18:11:55.090-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='objetos'/><category scheme='http://www.blogger.com/atom/ns#' term='poo'/><category scheme='http://www.blogger.com/atom/ns#' term='aggregation'/><category scheme='http://www.blogger.com/atom/ns#' term='delegation'/><category scheme='http://www.blogger.com/atom/ns#' term='silverbullet'/><title type='text'>Aggregation X Delegation - round 2</title><content type='html'>&lt;div&gt;De volta ao assunto do como montar objetos "compostos".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Como regra geral eu gosto bem mais da solução de Delegação. Acho mais elegante, mais conforme os princípios de OO, e de mais fácil compreensão também. Mas como eu já disse, isso é apenas minha opinião. E a sua, leitor, qual é?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;É fato também, que a solução de Agregação tem lá o seu lugar ao sol. Por exemplo: como definir o DisplayMember e o ValueMember de um WinForm.ComboBox com objetos compostos? Algo como ...&lt;/div&gt;&lt;br /&gt;&lt;div class="sourceCode"&gt;cboMeuComboBox.ValueMember = oMeuObjeto.SubObjeto.Id;&lt;br /&gt;cboMeuComboBox.DisplayMember = oMeuObjeto.SubObjeto.Descricao;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;... simplesmente não funciona. Nesse caso, eu acabo adotando a agregação, e fica mais ou menos assim:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="sourceCode"&gt;cboMeuComboBox.ValueMember = oMeuObjeto.SubObjeto_Id;&lt;br /&gt;cboMeuComboBox.DisplayMember = oMeuObjeto.SubObjeto_Descricao;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Isso mesmo, agrego as propriedades de SubObjeto diretamente como propriedades em MeuObjeto. É estranho e poluído, mas funciona 100%.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Atualmente eu tenho preferido sempre a solução de Delegação. Mas nesses casos mais particulares, não tem jeito... uso mesmo a Agregação. E claro, isso só comprova a nossa velha teoria, que "não existe bala de prata".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Até a próxima,&lt;/div&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5338802526972299762" border="0" alt="Leo Zacche" style="cursor: pointer; width: 80px; height: 15px;" src="http://2.bp.blogspot.com/_OVa5hAqn324/Shc8nLIkSfI/AAAAAAAAABI/XVmVQChV4BA/s200/LeoZacche_Pessoal.png"/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-2206806468237876785?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/2206806468237876785/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2009/06/aggregation-x-delegation-round-2.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/2206806468237876785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/2206806468237876785'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2009/06/aggregation-x-delegation-round-2.html' title='Aggregation X Delegation - round 2'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_OVa5hAqn324/Shc8nLIkSfI/AAAAAAAAABI/XVmVQChV4BA/s72-c/LeoZacche_Pessoal.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-7795698818725996551</id><published>2009-05-22T20:49:00.008-03:00</published><updated>2009-06-05T16:03:59.684-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ftp'/><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='clickonce'/><category scheme='http://www.blogger.com/atom/ns#' term='fileshare'/><category scheme='http://www.blogger.com/atom/ns#' term='publish'/><title type='text'>Bug Publicando ClickOnce via FTP</title><content type='html'>No VS2005, há um bug bem conhecido pelo pessoal que usa ClickOnce e publica via FTP: Ao final do processo, o VS simplesmente dá um erro e aborta. É bem chato, principalmente se você estiver fazendo testes de publicação... Toda hora tem que iniciar o VS de novo, abrir a sua solução de novo...&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Eu rodei a internet e nunca encontrei uma solução para isso. Até agora! É, porque hoje, por acaso, eu acabei descobrindo uma forma de impedir o bug de ocorrer...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Basta desmarcar a opção para exibir a página de deploy após a publicação (Propriedades do Projeto, aba Publish, botão Options, como figura abaixo). Feito isso, a publicação funciona numa boa... sem crash no final! Funciona tanto publicações FTP como file share (que tem o mesmo bug).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;img src="http://4.bp.blogspot.com/_OVa5hAqn324/Shc8AL16Y3I/AAAAAAAAABA/jjF51G7_BkY/s320/Uncheck+Open+Deploy+Page.jpg" style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 297px; height: 320px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5338801857147593586" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Eu ainda não testei no VS2008. Aliás nem sei se nessa versão corrigiram este bug. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;De qualquer forma, tomara que essa dica ainda ajude alguém.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Até a próxima!&lt;/div&gt;&lt;div&gt;&lt;img src="http://2.bp.blogspot.com/_OVa5hAqn324/Shc8nLIkSfI/AAAAAAAAABI/XVmVQChV4BA/s200/LeoZacche_Pessoal.png" style="cursor:pointer; cursor:hand;width: 80px; height: 15px;" border="0" alt="Leo Zacche" id="BLOGGER_PHOTO_ID_5338802526972299762" /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-7795698818725996551?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/7795698818725996551/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2009/05/bug-publicando-clickonce-via-ftp.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/7795698818725996551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/7795698818725996551'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2009/05/bug-publicando-clickonce-via-ftp.html' title='Bug Publicando ClickOnce via FTP'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_OVa5hAqn324/Shc8AL16Y3I/AAAAAAAAABA/jjF51G7_BkY/s72-c/Uncheck+Open+Deploy+Page.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-2626278127962936405</id><published>2009-05-09T20:25:00.008-03:00</published><updated>2009-06-05T16:04:47.987-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dbo'/><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='owner'/><category scheme='http://www.blogger.com/atom/ns#' term='sgbd'/><category scheme='http://www.blogger.com/atom/ns#' term='public'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><title type='text'>SQL Server - E porque eu gosto mais do Oracle (owner name)</title><content type='html'>Quem me conhece pessoalmente, sabe que eu prefiro o Oracle sobre o SQL Server. Não, eu não sou nenhum pregador anti-Microsft, nem defensor ferrenho de tecnologias OpenSource... nenhum desses blá-blá-blás "&lt;span style="font-style: italic;"&gt;anti-semitas&lt;/span&gt;". Eu tenho lás as minhas preferências, mas geralmente são baseadas em bons motivos técnicos.&lt;br /&gt;&lt;br /&gt;E hoje eu vou contar um dos motivos pelos quais eu gosto mais do Oracle do que do SQL Server. Para facilitar a compreensão, as espressões &lt;span style="font-style: italic; font-weight: bold;"&gt;usuário&lt;/span&gt;, &lt;span style="font-style: italic; font-weight: bold;"&gt;esquema&lt;/span&gt; e &lt;span style="font-weight: bold; font-style: italic;"&gt;owner&lt;/span&gt; são usadas com o mesmo significado.&lt;br /&gt;&lt;br /&gt;Em ambos os SGBDs você pode criar objetos (tabelas, views, procs, etc.) privadas (que são de um "usuário" em particular) ou públicas (de nenhum usuário em particular).&lt;br /&gt;&lt;br /&gt;Claro que há algumas diferenças de como os dois bancos interpretam essa questão, mas a regra geral é &lt;span style="font-style: italic; font-weight: bold;"&gt;se você não especifica o owner do objeto, está falando de um objeto que está no seu esquema (ou que pertence ao usuário corrente)&lt;/span&gt;. E daí tem os efeitos colaterais (positivos e negativos):&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Se você está criando um objeto, e não especifica o owner, ele será criado no seu usuário.&lt;/li&gt;&lt;li&gt;Se você está se referindo à um objeto, e não especifica o owner, está falando do objeto que existe no seu usuário. Se não existir no seu usuário, então vc está falando do público. Se não existir, é erro mesmo.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Até aí tudo bem, inclusive porque, como vocês sabem, e também por dedução lógica dos princípios acima, você pode "falar de um objeto" sem mencionar o owner, e o banco se encarrega de achar aquele que vai te servir.&lt;br /&gt;&lt;br /&gt;O detalhe sórdido é que o SQL Server tem uma exceção: Para functions, isso só funciona assim se o objeto é do dbo (público) e o usuário tem a role db_owner. Se não for assim, você é &lt;span style="font-weight: bold;"&gt;OBRIGADO&lt;/span&gt; a informar o owner da function.&lt;br /&gt;&lt;br /&gt;Ok, Léo, mas o que isso pega?&lt;br /&gt;Bem, respondo, se você trabalha em um ambiente não muito restrito, não vai pegar nada. Você vai usar o nome do owner e tudo bem. Já se você tem restrições, o bicho pega. Em locais que impõem regras rígidas de segurança (como empresas grandes, ou provedores de hospedagem), raramente você se conecta no SGBD com o mesmo usuário que é dono dos objetos.&lt;br /&gt;&lt;br /&gt;Ficou confuso né? ok, não sou um escritor experiente. Vamos a um exemplo prático:&lt;br /&gt;Eu estava criando um banco SQL Server que ia ser hospedado em um servidor de hospedagem. O cliente final é dono da conta e tem vários sistemas. Então ele tem um login dele (vamos dizer: "cliente"), e criou outro especificamente para este sistema (digamos "sistema1").&lt;br /&gt;&lt;br /&gt;Quando criei os objetos, não especifiquei owner, então ficou tudo assim: sistema1.tabelaA, sistema1.tabelaB, sistema1.viewC, sistema1.ProcD.&lt;br /&gt;&lt;br /&gt;Aí eu precisei criar uma função. E no código fonte, fui obrigado a dizer o owner da função. Só que o nomedo owner muda de acordo com o ambiente onde está sendo executado. Se é aqui dentro da empresa (onde é desenvolvido), o owner é um. Se é lá na hospedagem, o owner é outro. Então, restaram duas alternativas:&lt;br /&gt;&lt;br /&gt;Ou eu uso o owner exatamente igual tanto na hospedagem (ambiente de produção), quanto no desenvolvimento (o que nem sempre é possível, pq sempre temos que seguir regras de nomenclatura, que variam de empresa para empresa);&lt;br /&gt;&lt;br /&gt;Ou eu ignoro a possibilidade de usar mais de um usuário... e tudo passa a ser dbo. Como nesse caso, isso me traria menos problemas, essa foi a solução que adotei. Então mudei o owner de todos os objetos do banco para dbo (para quem não sabe, existe a &lt;b&gt;sp_changeobjectowner&lt;/b&gt; que faz isso, e eu montei um script fazendo um select diretamente no catálogo).&lt;br /&gt;E também tive que mudar os scripts de criação e alteração de TODOS os objetos para incluirem o prefixo "dbo.".&lt;br /&gt;E o código que acessa a function ficou "dbo.MinhaFuncao".&lt;br /&gt;&lt;br /&gt;Foi um saco, mas funcionou. Aí vai a manha:&lt;br /&gt;&lt;br /&gt;select 'exec sp_ChangeObjectOwner ''' + name + ''', ''dbo''' as cmd from sysobjects where xtype in ('U','FN','P')&lt;br /&gt;&lt;br /&gt;Tomara que ajude alguém.&lt;br /&gt;&lt;br /&gt;Até a próxima.&lt;br /&gt;LZ&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-2626278127962936405?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/2626278127962936405/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2009/05/sql-server-e-porque-eu-gosto-mais-do.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/2626278127962936405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/2626278127962936405'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2009/05/sql-server-e-porque-eu-gosto-mais-do.html' title='SQL Server - E porque eu gosto mais do Oracle (owner name)'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-623104596848465773.post-755855926033156008</id><published>2009-05-02T12:45:00.008-03:00</published><updated>2009-06-05T16:05:59.843-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='objetos'/><category scheme='http://www.blogger.com/atom/ns#' term='delegacao'/><category scheme='http://www.blogger.com/atom/ns#' term='poo'/><category scheme='http://www.blogger.com/atom/ns#' term='contencao'/><category scheme='http://www.blogger.com/atom/ns#' term='entidade'/><category scheme='http://www.blogger.com/atom/ns#' term='aggregation'/><category scheme='http://www.blogger.com/atom/ns#' term='agregacao'/><category scheme='http://www.blogger.com/atom/ns#' term='delegation'/><category scheme='http://www.blogger.com/atom/ns#' term='containment'/><category scheme='http://www.blogger.com/atom/ns#' term='silverbullet'/><title type='text'>Aggregation X Containment/Delegation</title><content type='html'>Eu sempre tenho essa dúvida na hora de construir meus objetos. Às vezes prefiro delegação. Outras Agregação. A quem é novo em POO, aqui vai um breve esclarecimento:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Problema:&lt;/strong&gt;&lt;br /&gt;Você tem uma entidade chamda "Cliente". Seus atributos são Nome, CPF e DataNascimento. Você também precisa de um atributo EstadoOrigem (unidade da federação onde o cliente se cadastrou). Você ia criar um atributo EstadoOrigem, do tipo string (onde você imagina armazenar a sigla, com dois caracteres), mas acabou de enxergar que Estado é um entidade tão importante no sistema, a ponto de ser representada realmente como uma entidade. :-)&lt;br /&gt;&lt;br /&gt;Você faz uma pausa em Cliente e modela a entidade Estado: NomeEstado e Sigla (vamos deixar todos os IDs fora de questão por enquanto, ok?).&lt;br /&gt;&lt;br /&gt;Com a entidade Estado na mão (que vai virar uma classe durante a programação), você olha de volta para cliente e pensa: Como vou representar o estado de origem do cliente?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solução 1: Agregação&lt;/strong&gt;&lt;br /&gt;Uma solução, chamada de Agregação, é &lt;em&gt;agregar&lt;/em&gt; os atributos da "sub-entidade" na "entidade-raiz". Ou seja: Cliente teria os seguintes atributos Nome, CPF, DataNascimento, NomeEstado, SiglaEstado.&lt;br /&gt;&lt;br /&gt;Efeitos colaterais? agora precisamos representar a UF de nascimento do cliente. Teríamos 2 NomeEstado e 2 SiglaEstado. Poderíamos nomear o segundo par de atributos como NomeEstadoNascimento e SiglaEstadoNascimento. O nome seria bastante claro, mas o primeiro par não está tão claro assim. Então seria melhor renomear o primeiro para NomeEstadoOrigemCadastro e SiglaEstadoOrigemCadastro.&lt;br /&gt;&lt;br /&gt;Alguns puristas diriam que esta abordagem fere um dos princípios básicos de origentação à objetos (encapsulamento). É verdade, eu também acho que fere, mas é um "mal necessário", às vezes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Solução 2: Delegação (ou Contenção ou Composição)&lt;/strong&gt;&lt;br /&gt;Outra solução é compor a entidade Cliente com outra(s) entidades, na forma de atributos. Então Cliente teria os seguintes atributos: Nome, CPF, DataNascimento e EstadoOrigem, sendo que EstadoOrigem tem os atributos NomeEstado e SiglaEstado.&lt;br /&gt;&lt;br /&gt;Nas linguagens de programação (a maioria) ficaria algo assim:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;txtValor.Text = objCliente.EstadoOrigem.NomeEstado&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Eu gosto mais dessa abordagem. Escreve-se menos, é mais clara (eu acho esse código mais limpo). Mas a prática mostra que isso tem lá os seus drawbacks.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Conclusão&lt;/strong&gt;&lt;br /&gt;Como eu já conheço alguns pontos positivos e negativos das duas formas, eu vou usando aquela que eu acho que vai se encaixar melhor em cada caso. Ou seja, eu não tenho uma solução única para todos os casos. "Não existe bala de prata", mas sim, a ferramenta certa para o trabalho certo.&lt;br /&gt;&lt;br /&gt;Eu vou voltar a este assunto mais tarde, mas antes queria saber das opiniões dos leitores... que abordagens preferem e seus motivos.&lt;br /&gt;&lt;br /&gt;Até a próxima.&lt;br /&gt;&lt;br /&gt;LZ&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/623104596848465773-755855926033156008?l=imaginarti.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://imaginarti.blogspot.com/feeds/755855926033156008/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://imaginarti.blogspot.com/2009/05/aggregation-x-containmentdelegation.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/755855926033156008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/623104596848465773/posts/default/755855926033156008'/><link rel='alternate' type='text/html' href='http://imaginarti.blogspot.com/2009/05/aggregation-x-containmentdelegation.html' title='Aggregation X Containment/Delegation'/><author><name>Léo Zacché</name><uri>http://www.blogger.com/profile/15531160469455242508</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='20' height='32' src='http://photos1.blogger.com/blogger/3473/4149/320/rosto_02.jpg'/></author><thr:total>0</thr:total></entry></feed>
