ImaginarTI

sexta-feira, 22 de maio de 2009

Bug Publicando ClickOnce via FTP

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...

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...

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).



Eu ainda não testei no VS2008. Aliás nem sei se nessa versão corrigiram este bug. 

De qualquer forma, tomara que essa dica ainda ajude alguém.

Até a próxima!
Leo Zacche

Marcadores: , , , ,

sábado, 9 de maio de 2009

SQL Server - E porque eu gosto mais do Oracle (owner name)

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 "anti-semitas". Eu tenho lás as minhas preferências, mas geralmente são baseadas em bons motivos técnicos.

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 usuário, esquema e owner são usadas com o mesmo significado.

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).

Claro que há algumas diferenças de como os dois bancos interpretam essa questão, mas a regra geral é 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). E daí tem os efeitos colaterais (positivos e negativos):
  1. Se você está criando um objeto, e não especifica o owner, ele será criado no seu usuário.
  2. 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.
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.

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ê é OBRIGADO a informar o owner da function.

Ok, Léo, mas o que isso pega?
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.

Ficou confuso né? ok, não sou um escritor experiente. Vamos a um exemplo prático:
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").

Quando criei os objetos, não especifiquei owner, então ficou tudo assim: sistema1.tabelaA, sistema1.tabelaB, sistema1.viewC, sistema1.ProcD.

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:

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);

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 sp_changeobjectowner que faz isso, e eu montei um script fazendo um select diretamente no catálogo).
E também tive que mudar os scripts de criação e alteração de TODOS os objetos para incluirem o prefixo "dbo.".
E o código que acessa a function ficou "dbo.MinhaFuncao".

Foi um saco, mas funcionou. Aí vai a manha:

select 'exec sp_ChangeObjectOwner ''' + name + ''', ''dbo''' as cmd from sysobjects where xtype in ('U','FN','P')

Tomara que ajude alguém.

Até a próxima.
LZ

Marcadores: , , , , ,

sábado, 2 de maio de 2009

Aggregation X Containment/Delegation

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:

Problema:
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. :-)

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?).

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?


Solução 1: Agregação
Uma solução, chamada de Agregação, é agregar os atributos da "sub-entidade" na "entidade-raiz". Ou seja: Cliente teria os seguintes atributos Nome, CPF, DataNascimento, NomeEstado, SiglaEstado.

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.

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.


Solução 2: Delegação (ou Contenção ou Composição)
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.

Nas linguagens de programação (a maioria) ficaria algo assim:

txtValor.Text = objCliente.EstadoOrigem.NomeEstado

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.


Conclusão
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.

Eu vou voltar a este assunto mais tarde, mas antes queria saber das opiniões dos leitores... que abordagens preferem e seus motivos.

Até a próxima.

LZ

Marcadores: , , , , , , , , ,