Archive for July, 2008

Banco de Dados e Null values 0

É comum na modelagem de banco de dados termos colunas com valores nulos. Para tipos como string, que são “reference type”, valor null é extremamente comum, mas e quanto a valores primitivos como: int, float, double, DateTime (struct no C#) e entre outros?

Na versão 2.0 do .NET, sim numa versão já adotada no mercado (.NET 1.1 é bem pouco, espero) apresentou o conceito de Nullable Types que permite você inferir valores nulos à built-in types (ou tipos primitos). Não irei entrar em detalhes muito profundos, pois pretendo ser breve nest post.

A sintaxe é bem simples:

   1: int? a = null;
   2:  
   3: // dois properties para Nullable Types, HasValue e Value
   4: if (a.HasValue) Console.WriteLine(a.Value);

Assim podemos atribuir valores para nulos e não mais valores default para estes tipos de dados.

Ok, isso é bonito mas o IDataReader não possui um método para tratar quando valores são nulos, o que fazemos? Realizamos uma checagem com o método IsDbNull, e se for podemos retornar nulo ou o valor caso OK. Veja abaixo:

   1: int? coluna = reader.IsDBNull(i) ? (int?)null : (int?)reader.GetInt32(i);

Isso resolveria o nosso problema, mas e se tivermos 10 colunas na tabela, esse código polui um pouco, não? Pena que o GetInt32(int i) não lida com campos nulos.

Como podemos melhorar isso?

Podemos usar Extension Methods!

Num post anterior eu cheguei a falar bem básicamente sobre extension methods, veja como resolveríamos este problema:

   1: static class DataReaderTypeHelper
   2: {
   3:     public static int? GetNullOrInt32(this IDataReader reader, int index)
   4:     {
   5:         return reader.IsDBNull(index) ? (int?)null : (int?)reader.GetInt32(index);
   6:     }
   7:  
   8:     public static string GetNullOrString(this IDataReader reader, int index)
   9:     {
  10:         return reader.IsDBNull(index) ? null : reader.GetString(index);
  11:     }
  12:  
  13:     public static DateTime? GetNullOrDateTime(this IDataReader reader, int index)
  14:     {
  15:         return reader.IsDBNull(index) ? (DateTime?)null : (DateTime?)reader.GetDateTime(index);
  16:     }
  17: }

Agora podemos este método e tornar a coisa mais bonita e direta:

   1: int? coluna = reader.GetNullOrInt32(index);

Muito mais simples, fácil e direto de usar. Podemos fazer também para inserção, remoção ou atualização onde valores nulos encrencam no banco de dados também. Normalmente teríamos que fazer:

   1: cmd.Parameters.AddWithValue("@param1", param1);
   2: cmd.Parameters.AddWithValue("@param2", param2);

Se usassemos o código acima, se @param2 pudesse ser nulo no banco de dados, este código geraria uma SqlException caso o valor de param2 fosse nulo, pois o null do c# é diferente do null para o banco de dados, então teríamos que verificar o valor e assim retornar DBNull.Value.

Com Nullable Types, isso ficaria extremamente simples, nada de if‘s:

   1: cmd.Parameters.AddWithValue("@param2", (object)param2 ?? DBNull.Value);

Observe que temos de fazer um cast para object em param2, pois para o compilador o operador ?? deve garantir que param2 e DBNull.Value sejam do mesmo tipo, por que Nullable usa Generics para inferir tipos, embora mascare isso.

Usando novamente Extension Methods podemos fazer uma classe que nos ajude nisso:

   1: static class DbHelper
   2: {
   3:     public static void AddWithValueOrNull(this SqlParameterCollection collection, string param, object value)
   4:     {
   5:         collection.AddWithValue(param, (object)value ?? DBNull.Value);
   6:     }
   7: }

Agora temos um método AddWithValueOrNull para o Parameters que é do tipo SqlParametersCollection. Assim encapsulamos tudo numa sintaxe mais limpa:

   1: cmd.Parameters.AddWithValueOrNull("@param2", param2);

Nota usamos este method apenas para valores que possam ser nulos e não para todos, no caso de chaves primárias devemos usar o AddWithValue mesmo por que devemos reforçar a necessidade de valores não nulos.

Insert Code Snippet plugin para Windows Live Writer 0

Testando…

   1: // must add reference to System.Configuration
   2: string connectionString = ConnectionManager.ConnectionStrings["MyConnection"].ConnectionString;
   3: // creating connection
   4: SqlConnection connection = new SqlConnection(connectionString);
   5: // creating a command
   6: SqlCommand command = connection.CreateCommand();
   7: command.CommandText = "SELECT * FROM [MyTable]";
   8: SqlDataAdapter adapter = new SqlDataAdapter(command);
   9:  
  10: // creating DataTable
  11: DataTable dt = new DataTable();
  12: adapter.Fill(dt);
  13:  
  15: foreach (DataRow row in dt.Rows)
  16: {
  17:     Console.WriteLine(row.Field<Guid>(dt.Columns["primary_key"]));
  18: }

Muito Legal!

Sem estilo

   1: // without embed styles
Dentro de um container
   1: // without container
Sem container mas com estilo
   1: line 1
   2: line 2

Projetos do Visual Studio com Subversion 6

Baseado no post anterior, pretendo escrever uma série de posts usando o TortoiseSVN para trabalhar com controle de versão num projeto que estou realizando, que se der pretendo colocar minhas experiências aqui, mas isto fica para outros posts.

O Visual Studio não possui integrado outros controles de versão senão o Visual Source Safe (VSS) da própria Microsoft. Eu já trabalhei com o VSS numa empresa o qual estagiei, mas era disponível para desenvolvimento numa rede local. Ter um servidor rodando Windows e com o VSS não é nada comum. Por este motivo optei pelo Subversion.

No post anterior, expliquei sobre como importar um projeto no repositório, dar checkout e realizar um commit simples. Agora vou citar algumas configurações que devem ser feitas quando lidamos com solutions do Visual Studio.

Uma solução é composta de 1 ou mais projetos, estas informações ficam no arquivo *.sln. Cada projeto é compilado e gera dois diretórios bin e obj. Estes arquivos não são de interesse ao controle de versão, uma vez que a responsabilidade dele é apenas gerenciar códigos.

Portanto, devemos eliminar estes diretórios do repositório para isso utilizamos properties do SVN, usando a property svn:ignore.

A configuração do property é particular de um diretório e fica registrado nos arquivos contidos no diretório .svn (ou _svn) que só podem ser vistos se alterar a visualização de arquivos do Windows para exibir arquivos ocultos. Pelo fato desta configuração ser inserida nestes diretórios, ao criarmos um projeto novo que não esta no repositório, esta informação não fica registrada para este projeto, resultando na adição dos diretórios bin e obj. Seria necessário selecionar manualmente cada arquivo que seria submetido excluindo tudo que tem relação com o diretório bin e obj.

Para este problema podemos declarar globalmente o que remover. Assim teremos de remover os seguintes arquivos para uma solução no SVN:

bin obj *.suo *.user

  • bin e obj – são diretório de arquivos binários (compilados)
  • *.suo – corresponde às configurações de usuário para a solução
  • *.user – corresponde às configurações de usuário para o projeto

 

A seguir vou apresentar como realizar cada operação (inserindo properties e global ignore) e comentários sobre problemas que tive e como tratei eles.

Ignorando Diretórios e Arquivos no Subversion

Num diretório com o projeto gerenciado pelo SVN, clique com o direito e TortoiseSVN > Properties, como ilustra a figura abaixo:

tsvn_04 

Em seguida vamos adicionar uma properti svn:ignore com valores

bin obj *.suo *.user

Com espaços entre cada entrada. Marque a opção: Apply property recursively. Isso irá aplicar a todos os subdiretórios recursivamente a mesma property facilitando o trabalho de ter que replicar a mesma configuração para todos os diretórios.

Entretanto, os diretórios que não estão sobre controle (sem .svn/_svn) não terão esta restrição, entao ao dar um Add os arquivos não desejados serão adicionados, sendo necessário fazer a seleção manual. Para este problema a melhor solução é usar configurações globais de ignore aplicando isso a qualquer diretório.

tsvn_03

Ignorando Globalmente Arquivos e Diretórios

Vá em TortoiseSVN > Settings

tsvn_01

Adicione os elementos “bin obj *.suo *.user” como feito acima em “Global ignore patterns

tsvn_02

Agora o trabalho de dar Add simplificou, garantindo que será adicionado apenas arquivos de código ou necessários para a solução.

Problemas e Soluções

Um dos detalhes que tem que se considerar quando se trata de Visual Studio é que os arquivos que gerenciam os arquivos de solução e projeto, são atualizados somente se for realizando um build da solução e projeto.

Por exemplo, se adicionamos uma referência a um projeto ou *.dll o arquivo que gerencias estas referências será alterando somente se houver alguma classe que referêncie a ela, usando o using por exemplo.

Da mesma forma, para remover uma referência não utilizada mais, é preciso removê-la do references e em seguida executar um Build do projeto ou solução para que as alterações sejam registradas no arquivo e assim resultar numa nova versão do arquivo.

Outra situação é se você já deu commit nos arquivos que devem ser ignorados. O jeito é removê-los antes de aplicar o ignore, senão você não terá como dar commit nos arquivos deletados. Realize estas operações com a solução fechada no Visual Studio.

Uma vez corrigido você poderá aplicar as restrições e assim colocar ordem no repositório.

Usando TortoiseSVN como cliente para o Subversion 2

Todo desenvolvedor um dia irá trabalhar em equipe e não há como trabalhar sem um controle de versão. Temos vários sistemas para esta tarefa mas há dois principais: CVS (Concurrent Versions System) e SVN (Subversion). Entre eles o SVN, do que vejo, tem sido o mais usado.

Novamente, como no post anterior sobre o Grep, sou usuário Windows e interface é mais prático que linha de comando, pelo menos para mim.

Em termos de cliente para SVN o TortoiseSVN é o mais popular, e é mantido pelo próprio pessoal do SVN.

Pretendo, nos próximos posts mostrar como usar ele para trabalhar. Já trabalhei com Eclipse e Netbeans quando programei em Java e ambos integram diretamente com o IDE tanto para CVS como SVN.

No momento estou realizando um projeto em .NET usando Visual Studio, e infelizmente ele só trabalha com o Source Safe (da Microsoft) como controle de versão, não sendo possível usar o SVN nem o CVS diretamente. Existem soluções para isso, mas não é o intuito deste post.

Este post também não pretende mostrar como configurar um servidor local SVN, pode ficar para um outro post.

Baixe o TortoiseSVN aqui.

Importando o Projeto Inicial

Agora vou entrar num ponto em que me confundiu demais e acredito para outros também. No SVN o Import refere-se a Importar um projeto ao SVN e não importar um projeto do SVN, como da-se a entender.

Selecione o diretório com o projeto existe e clique com o botão direito sobre ele e TortoiseSVN > Import

tsvn_01

Uma janela irá aparecer e será pedido a URL do servidor SVN e uma mensagem import.

Checkout

Uma vez feito isso é possível realizar o primeiro Checkout. O Checkout irá baixar uma versão do repositório podendo ser HEAD (a corrente) ou uma versão qualquer existente. Cada commit corresponde a uma versão.

Crie um diretório e com o botão direito Checkout SVN…

Após o checkout o diretório irá ficar marcado com um símbolo de OK.

tsvn_02

Adicionando Arquivos ao Repositório

Crie um arquivo no diretório o qual o projeto está guardado e clique em TortoiseSVN > Add.

Um sinal de “+” será marcado no arquivo dizendo que ele foi adicionado. Isso é necessário sempre que um novo arquivo for criado. O diretório com alterações ficará marcado com uma “!”

tsvn_03

Feito esta etapa o arquivo ainda não foi submetido ao repositório, para isso é necessário realizar um commit.

TortoiseSVN > Commit

Será pedido uma mensagem identificando o motivo do commit. É importante ser claro e objetivo para que quando necessário retornar um versão saber a que ela representa.

Uma vez realizado o commit a revisão será incrementada e o diretório ficará marcado com um OK novamente.

Até um próximo post sobre o TortoiseSVN.

Buscando palavras em arquivos com Windows Grep 2

Mudando um pouco o estilo do blog que era postar coisas técnicas, apesar de não ter feito isso ultimamente.

Recentemente tive que implementar um driver para um projeto do curso de Sistemas Operacionais que estou fazendo. O sistema operacional estudado é o Minix 3 que é opensource é apresenta elementos básicos de sistemas operacionais.

Entretanto, minha experência com C é muito básica, e é um tanto chato ficar varrendo arquivos e arquivos, mesmo usando o visual studio, para ir atrás de referências ou coisas do tipo. O intellisense para C/C++ não é tão bom como para C#, mas ajuda bastante.

O que precisei fazer era ficar buscando palavras ou códigos que usassem determinada rotina para fazer inspeção de código e entender como o mecanismo funciona.

Apesar de Visual Studio ter o “Find All References” ele não funciona muito bem. Tem também a opção de usar o Ctrl+F e fazer um “bookmark all” de todas as buscas, mas não sei por que diabos ele não funciona para buscam no projeto, ele só vale para o “Current Document”.

Para o pessoal do linux os shells scripts (ou qualquer outro script) são poderosos. O pessoal do Windows é meio ignorante com linha de comando. Eu estou tentando usar o shell mas as vezes demoro muito para fazer coisas simples, mas é so tentando que se aprende. Nós sempre precisamos de uma alternativa gráfica, por que é muito mais simples e prático.

Pensando nisso estou escrevendo sobre o Windows Grep ou wingrep que faz esse serviço para nós.

mainwindow1

Você coloca os diretório de onde quer buscar e escreve a expressão regular que deseja como filtro e esperar ele fazer a busca. Uma coisa muito boa é que ele lista arquivo por arquivo e mostra trechos de código do arquivo. Vale a pena.

Existe também uma versão do grep para console, não tem muito segredo o código, mas coisa que notei que o windows não vem! Eu usava no meu PC achando que era nativo do windows até usar outro computador e não existe o comando. No lugar dele usa-se o find.

Nota. Não estou ganhando nada pela divulgação, apenas sugerindo uma ferramenta que todo mundo deveria ter.

Até um próximo post!