Como descobrir quais tabelas foram modificadas recentemente

Depois de semanas sem postar, vou colocar um post bem breve aqui sobre SQL.

Recentemente precisei descobri quais tabelas foram modificadas recentemente sem ter que ver uma a uma. Se você tivesse poucas tabelas, isso não seria um problema, ver uma-a-uma, digamos umas 15 ou 20 seria até rápido. Mas podemos facilitar um pouco a nossa vida, limitando nossa amostra.

Isto aqui vale para SQL Server, não sei como seria em outras databases (Oracle, Postgree, MySQL e etc).

No SQL Server temos várias Views de sistema, no caso usaremo a View sys.tables, que nos fornece informações diversas sobre as tabelas do banco de dados.

SELECT * FROM sys.tables

Executando um select sobre esta tabela obteremos um resultado semelhante a este:

sys_tables1

A imagem mostra apenas algumas colunas, existem muitas outras, mas vamos nos focar naquelas que precisamo no momento.

Veja que temos os nomes de todas as tabelas, e duas colunas de datas, create_date e modify_date.

A primeira instância, achariamos que teríamos que observer a tabela modify_date e ordenar por ordem decrescente por ela.

SELECT * FROM sys.tables ORDER BY modify_date DESC

Infelizmente, a informação de data de modificação refere-se a inserção de dados, e não sobre sua estrutura.

sys_tables2

A coluna que temos que ver é create_date. Na figura não é possível observar isso, mas a data contida em create_date refere-se a última modificação estrutural realizada sobre ela.

Então bastaríamos fazer:

SELECT * FROM sys.tables ORDER BY create_date DESC

Eu sei que este post não é muito informativo, é mais uma dica.

Abraços e até o próximo post.

Posted in dica, solucao, sql server, t-sql | 1 Comment

Testing…

Postando uma mensagem de teste.

Blog: Developer Studies Testando italic e bold

citation…

Using another editor blog…

Windows Live Writer I miss you.. I need a code editor support…

Posted in Uncategorized | Leave a comment

Delegates em C# (Ponteiros de Função)

Recentemente recordei uma das dificuldades que tive quando entrei no mundo .NET, aliás minha experiência era extremamente limitada se comparada a hoje, apesar de ter muita coisa para estudar.

Pretendo neste post abordar um tópico muito importante do .NET framework que poucas pessoas usam ou desconhecem.

Quem já programou em linguagens como C/C++ isso não deve ser um problema, a menos que tenha feito somente algoritmos básicos de estrutura de dados (pilhas, filas, listas e etc).

Delegates é nada mais nada menos que um ponteiro para função. Ponteiro para muitos é um pesadelo, eu ainda tenho dificuldade quando começo a escrever um programa em C, sempre me esqueço das notações, pois em linguagens de alto nível como Java e C# elas ficam escondidas.

Bom, entenda da seguinte maneira, digamos que você possua uma subrotina/função, se você souber onde ela se encontra em memória é possível invocá-la. Um ponteiro é um endereço para uma região da memória, no caso do delegate é ponteiro para uma subrotina/função.

A questão é que em C# as coisas são tipadas, quando você define um delegate você define um contrato com quem quer “disponibilizar” um rotina ou função.

A sintaxe é a seguinte:

delegate <return_type> MyDelegate(<params>);

Por exemplo:

delegate int Calcula(int a, int b);

Podemos referenciar um função qualquer que aceite dois inteiros e retorne um inteiro como resultado, poderiamos utilizar:

public int Soma(int num1, int num2)
{
    return num1 + num2;
}

Agora definimos que um ponteiro para essa rotina da seguinte forma:

Calcula calc = Soma;

Simples, nâo?

Antigamente para eventos usava-se a seguinte nomenclatura:

Calcula calc = new Calcula(Soma);

Com o C# 2.0 podemos fazer assim:

Calcula calc = delegate(int a, int b)
{
    return a * b;
};

Ou podemos fazer, neste caso estranho:

Calcula calc = delegate
{
    return 2; // magic number detected!
}

O exemplo acima é meramente ilustrativo.

Ok, agora que conhecemos as sintaxes vamos conhecer alguns delegates muito úteis já existentes no C#:

  • Action (C#2)
  • Predicate (C#2)
  • Func (C#3)

Action

Action corresponde a uma ação a ser executada sobre um valor, onde T define o tipo de valor. Se você nâo conhece generics, sugiro que estude um pouco, não é nada complicado, só não entrarei em detalhes por que não é o escopo deste texto.

O action recebe um parametro do tipo T, por exemplo:

Action<string> printText = delegate(string s)
{
    Console.WriteLine(s);
};

Invocando:

printText("Hello World");

Simples não? No caso, podemos alterar o valor de ‘s’, pois ‘s’ é um reference type, ou seja, poderiamos tratar o texto, retirando por exemplo, todas as vírgulas do texto:

Action<string> removeVirgula = delegate(string s)
{
    s.Replace(",", string.Empty);
};

removeVirgula(“Hello, World”); // produz Hello World

Predicate

A predicate is the portion of a clause, excluding the subject, that expresses something about the subject.

Predicate ou predicado corresponde a uma clausula a qual expressa alguma coisa.

Digamos que desejamos saber se um número é par (even):

Predicate<int> even = delegate(int number)
{
    return number % 2 == 0;
};

even(2); // true
even(3); // false

Veja que retornamos um booleano para predicates, pois desejamos saber se o ‘number’ que foi passado a rotina expressa o que meu predicado quer, no caso saber se o número é par.

Func (C#3)

E por último, existente apenas no C# 3.0 o Func. Diferente do Action e Predicate, o Fund possui 5 variações:

Func<TResult>
Func<T, TResult>
Func<T1, T2, TResult>
Func<T1, T2, T3, TResult>
Func<T1, T2, T3, T4, TResult>

Bom, as assinaturas são muito claras e são lidas da seguinte forma: o tipo de retorno e nenhum parâmetro ou o tipo de retorno com 1 a 4 parâmetros.

Acredito que o número de parâmetros são mais que suficientes, se a rotina começar a ter mais que esse número de parâmetros é possível que ela esteja fazendo mais coisas do que precisaria e podendo ser sub-divida em menores rotinas, facilitando tanto a leitura como reuso. Se você ainda assim achar que precisa de mais, bastaria criar uma outra assinatura com N parâmetros.

Ok, você poderia pensar em fazer uma Func que tratasse a string e não retornasse nada por exemplo. Entretanto, esse tipo de retorno não é possível. Se você pretende usar Func<> você deve fato deseja retornar um valor.

Quando lembro de function e subroutine me recordo de um trecho do texto do livro Code Complete 2nd Edition onde diferenciava o uso das duas palavras.

Function: é como definido na matemática, y = f(x), onde f é uma função. Ou seja, a função recebe um parâmetro e retorna um valor por definição.

Subrountine: já sub-rotina corresponde a uma tarefa a ser realizada, e não retorna valor. Se você já programou em Visual Basic deve ter notado a distinção delas.

Bom, voltando. O correto se deseja usar um delegate com retorno void seria Action, porém ele só possui 1 parâmetro. Mas segundo este link me parece que futuramente será extendido para mais parâmetros como o Func.

O uso é praticamente o mesmo como mostrado para predicate e action, sendo um mix de ambos.

Func<int, int, int> sum = (a, b) => a + b;

sum(1, 2) // return 3

Se não tivermos parâmetro algum, podemos usar:

Func<object> CreateObject = () => { return new object(); }

object o = CreateObject();

Observe que as delegates predefinidas como Action, Predicate e Func não precisam ser obrigatóriamente usadas, você pode criar suas próprias assinaturas como foi feito no início deste post, mas se for possível usar as já existentes use, pois é uma linguagem comum para todos os programadores em C#, poderíamos ter um delegate Process<T> igual a Action<T>, se usasse Action, seria muito claro o que pretende-se fazer. Não é uma regra, mas sempre que possível use as já predefinidas.

Bom, o post ficou bem grande, tentei ser o mais detalhado e claro possível. Até um próximo post.

Posted in .NET, C#, C#3 | 4 Comments

Proxy Pattern: Exemplo e Aplicação

Desde meu último post acabei não cumprindo com o que esperava. Como já devo ter mencionado, estou cursando Engenharia da Computação Cooperativo, onde o curso intercala módulo acadêmico e estágio, permitindo tempo integral (desde que não tenha DPs para pagar). Comento sobre isso em outro post, vamos voltar ao assunto.

Depois de realizar meu primeiro laboratório de engenharia de software, não adotar um framework na minha camada de persistência tornou muito trabalhoso sua modelagem e manutenção. Cada operação exigia escrita em código ou stored procedure o que tornava “uma tarefa simples” em trabalhosa, não que demorasse muito, mas depois de muitas linhas de coisas para coisas tão banais o processo ficava um tanto… chato.

Desde então, tenho como objetivo aprender um framework para essa finalidade. Claro, não podia ficar de lado o Hibernate, mas no momento estou curtindo C# e no caso temos o NHibernate. Conversei com um colega do trabalho e ele aparentemente não gostou muito do NHibernate. Não entrei muito em detalhes do por que ele era ruim, mas a comparação era bem direta se comparado com o Hibernate do Java. Portanto, ele costuma usar o ActiveRecord que usa como base o NHibernate.

Mas nas últimas semanas saiu o NHibernate 2.0, apesar de a página não estar atualizada. E concerteza deve ter melhorado em muitos aspectos. Por isso escolhi o NHibernate como estudo. Pretendo falar mais sobre ele em outro post (quando der).

Resumo

O uso do (N)Hibernate é bem direto, use POJO (plain old java object) ou POCO (plain old c# object), onde os objetos contém basicamente get/set. Talvez minha definição esteja um tanto incompleta, então me corrijam se falei absurdos.

No Java todos os métodos por default podem ser overrided, bastando reescrevê-lo em sua classe estendida. Já no C# a coisa fica mais explicita. Por default nenhum método/property pode ser overrided, para tal é necessário acrescentar a keyword “virtual”, e quando realizamos um override a keyword “override”, já veremos um código.

O que quero dizer com isso? Bem, como no Java isso já é default para todos os objetos então só é necessário definir os getters e setters da classe, já para o NHibernate todos os properties devem vir com a keyword virtual, caso contrário a coisa não funciona.

Então me perguntei: por que tenho que colocar todas as properties como ‘virtual’?

Bom, inicialmente achei que o NHibernate deveria simplesmente instanciar um objeto da entidade mapeada e então preencher todos os properties um a um. Mas o (N)Hibernate existe uma funcionalidade chamada de Lazy Load.

O que é Lazy Load?

Serei bem breve, digamos que você tenha um objeto e este possui uma referência para um outro objeto, seria um desperdício recurarmos o estado do objeto referenciado se nem usassémos ele. O que o lazy load faz é carregar este objeto (realizar a query no banco de dados) realmente quando precisamos. Mas como diabos isso ocorre?

A resposta é usando Proxy Pattern.

O que ele faz é atuar como um proxy entre a chamada de um property/método. Uau, entendi nada, o que é proxy?

Eu sempre me perguntava isso. Um proxy é digamos um “passo” intermediário de um fluxo. O exemplo mais comum é em redes de computadores. Digamos que sua máquina acesse a internet diretamente, ou seja, o seu computador e a “nuvem”. Se quisessemos realizar um filtro no neste tráfego, poderíamos utilizar um serviço de proxy que atua entre a nuvem e seu computador, de modo que todas as requisições passem sempre pelo proxy, tratando os dados trafegados e aplicando filtros adequadamente.

Como implementamos um proxy pattern? Veja um exemplo bem simples abaixo:

   1: public class MyClass
   2: {
   3:     public virtual string Message { get; set; }
   4:  
   5:     public virtual void DoSomething()
   6:     {
   7:         Console.WriteLine("Doing something really important.");
   8:     }
   9: }
  10:  
  11: public class MyClassProxed : MyClass
  12: {
  13:     public override string Message
  14:     {
  15:         get
  16:         {
  17:             Console.WriteLine("Proxying on reading...");
  18:             return base.Message;
  19:         }
  20:         set
  21:         {
  22:             Console.WriteLine("Proxying on saving...");
  23:             base.Message = value;
  24:         }
  25:     }
  26:  
  27:     public override void DoSomething()
  28:     {
  29:         Console.WriteLine("Proxying DoSomething() before");
  30:         base.DoSomething();
  31:         Console.WriteLine("Proxying DoSomething() after");
  32:     }
  33: }

O que basicamente fazemos é extender a classe MyClass criando uma MyClassProxed dando override nos métodos e properties. Para testarmos, seria muito simples:

   1: MyClass myClass = new MyClass() {Message = "Hello World!"};
   2:  
   3: Console.WriteLine("Normal behavior");
   4: Console.WriteLine("MyClass.Message = {0}", myClass.Message);
   5: Console.Write("MyClass.DoSomething()");
   6: myClass.DoSomething();
   7:  
   8: Console.WriteLine();
   9:  
  10: Console.WriteLine("Normal behavior plus proxying");
  11: myClass = new MyClassProxed() {Message = "HelloWorld!"};
  12: Console.WriteLine("MyClass.Message = {0}", myClass.Message);
  13: Console.Write("MyClass.DoSomething()");
  14: myClass.DoSomething();

Como a classe MyClassProxed extende a class MyClass basicamente a interface não muda, logo do nosso ponto de vista qual implementação usamos não importa, seja MyClass ou MyClassProxed, para nós o que importa é a interface da property Message e o método DoSomething(). O resultado esperado é algo como:

proxy

Conclusão

Utilizando este pattern é possível realizar o lazy load de forma transparente para o desenvolvedor.

Esse pattern é bem conhecido e pode ser encontrado no livro Design Patterns, Elements of Reusable Object-Oriented Software do GoF (Gang Of Four), que por sinal é uma leitura básica para qualquer desenvolver.

Infelizmente, o conteúdo do livro não é de fácil digestão quando sua experiência como desenvolvedor é pequena, muitos patterns não fazem sentido pois você não consegue comporrender os problemas de implementação que existem.

Espero poder dar continuidade neste tipo de post, até uma próxima vez.

Posted in .NET, C#, designpatterns, NHibernate, oop | 2 Comments

Acabaram as aulas… de volta a ativa!

Com 1 dia de atraso, informo que estou de volta a ativa. Essas últimas duas semanas e 1 dia foram extremamente carregadas para mim na faculdade (POLI-USP). Foram muitas provas e trabalhados que ficaram agrupados num curto espaço de tempo. Ontem, foi o último dia e não escrevi por que eu não dormi, de domingo para segundo, pois estava tentando fechar a apresentação de um projeto de software para segunda. Infelizmente não foi possível concluí-lo, mais um dia e teríamos concluído.

De fato, isso é muito ruim do ponto de vista comercial, se pensarmos que a data de prazo não foi possível concluir o sistema. Entretanto, eu não tive um mês dedicado para executar o projeto, tinha que organizar o horário, aula-provas-trabalhos de outras matérias também. Bom, chega disso.

Com esse termíno estarei em tempo integral em período de estágio e com isso tenho mais liberdade para voltar a escrever e estudar coisas novas!

Como hoje é so o primeiro dia, aproveitei ontem para recarregar as energias e poder voltar a me integrar no mundo tecnológico o qual estive por fora nas últimas duas semanas.

Só para encerrar o post, para quem ainda não viu, brinquem com o Photosynth da Microsoft, é muito divertido e incrível o que ele faz!

Abraços e até um próximo post.

Posted in Uncategorized | 1 Comment

Programando para Office 2007 com C#… que nada, VB.NET!

Não você não leu errado, escrevi VB.NET (Visual Basic dot Net), isso mesmo.

Eu nunca pensei que algum dia programaria em VB, já programei com VBScript na primeira versão do ASP (há muitos anos atrás), nem conhecia PHP. Nesta época, eu procurava por uma forma de fazer páginas dinâmicas, que para mim naquela época pensava: “Essas páginas HTML não fazem p@&*# nenhuma?”, então tinha que ver um jeito de resolver isso. Depois migrei para PHP onde gostei mais, por haver servidores públicos abertos (open source a bla-bla-bla), mas essas histórias ficam para outro post.

Bom, já tive de programar com VBA para Excel, cheguei a escrever um post sobre isso, minha experiência não foi boa, apesar de ter concluído tarefa que tinha de fazer.

Mas VBA é coisa do “passado”, a partir do Office 2003 foi incorporado o VSTO (Visual Studio Tools for Office) que permite fazer coisas mais “bacanas”, assim dizendo, através de addins para o Excel (posso estar completamente errado, talvez isso já exista a nos e para mim é coisa nova).

Como a plataforma é .NET, fica a escolha do programador escolher entre C# ou VB. Entretanto para esses tipos de desenvolvimento em particular, acredito que para o pessoal do VB a tarefa seja um tanto mais, prática.

Eu nunca gostei da sintaxe do VB, acho muito poluído, odeio o esquema de declaração de váriaveis:

   1: // VB
   2: Dim texto As String = "texto"
   3: Dim conn As SqlConnection = New SqlConnection(cs)
   4:  
   5: // C#
   6: string texto = "texto";
   7: SqlConnection conn = new SqlConnection(cs);

Argh, coisa feia! Em termos de tamanho não varia muito, mas em clareza e facilidade de leitura prefiro o C#.

Mas vou dizer aqui algum dos motivos do por que VB é melhor que C# para desenvolvimento Office:

  • VBA para VB é parecido (senão igual);
  • Todos as macros de VBA são facilmente portáveis para VB ;
  • Passagem de parâmetros para rotinas “dinâmico”;
  • Properties ou métodos diretos, como: Value e Offset

Até onde eu estou estudando essas foram os grandes motivos de se trabalhar com VB.

   1: // VB
   2: Dim wb As Excel.Workbook = Me.Application.Workbook
   3: Dim ws As Excel.Worksheet = wb.Sheets(1)
   4:  
   5: Dim range As Excel.Range = ws.Range("A1") // posso passar apenas row ou (row, col)
   6:  
   7: // C#
   8: Excel.Workbook wb = this.Application.Workbook;
   9: Excel.Worksheet ws = wb.Sheets[1];
  10:  
  11: Excel.Range range = ws.get_Range("A1", missing); // tenho que preencher todos

Em C#, eu preciso passar todos os campos, ou seja, quando não desejado é preciso passar “missing”. Também não temos um método direto como Range(cell, cell). Temos que usar os métodos, set_Range, get_Offset entre muitos outros.

Outro ponto que é irritante também é em rotinas:

   1: // VB
   2: Dim ws As Excel.Worksheet = ...
   3: ws.Protect("password") // simples e direto
   4: // quero content como false
   5: ws.Protect("password", Content := False) // indolor
   6:  
   7: // C#
   8: Excel.Worksheet ws = ...;
   9: // preciso passar todos os parametros
  10: ws.Protect("password", missing, missing, missing, ..., missing);
  11: // quero content como false
  12: ws.Protect("password", missing, false, missing, missing, ...); // meu deus...

Infelizmente para o pessoal do C# trabalhar com Office fica um tanto irritante.

Por este motivo acho que trabalhar com VB agiliza e facilita as coisas, embora tenha que aprender como é a sintaxe do VB, mas aposto que o ganho será muito maior do que ter que programar em C#.

Posted in .NET, C#, office, VB, visual studio | Leave a comment

Banco de Dados e Null values

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

Posted in .NET, C#3, dica | Leave a comment

Insert Code Snippet plugin para Windows Live Writer

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
Posted in Uncategorized | Leave a comment

Projetos do Visual Studio com Subversion

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.

Posted in .NET, svn, tutorial, visual studio | 6 Comments

Usando TortoiseSVN como cliente para o Subversion

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.

Posted in dica, svn, tutorial | 3 Comments