O T4 é uma ferramenta da Microsoft que pode ser utilizada para geração de código fonte. Neste post vamos mostrar o poder dessa ferramenta junto com o Entity Framework e o quanto você pode agilizar seu processo de desenvolvimento com ela.

Nota: Caso você não saiba muito bem como trabalhar com o Entity Framework, a DevMedia possui esses ótimos cursos sobre o tema:

Criaremos um CRUD básico utilizando o T4. Primeiro você precisa de uma base de dados SQL Server para que possamos implementar, ou faça o download da base que está disponível junto com o código fonte do artigo. Abra o Visual Studio e crie um novo projeto clicando em File -> New -> Project, conforme a Figura 1.

Figura 1. Criando um novo Projeto.

Na janela seguinte digite “empty” na caixa de pesquisa e selecione BlankSolution e altere a propriedade Name para FirstT4Entity ou para nome que preferir, conforme mostra a Figura 2.

Figura 2. Criando uma Blank Solution(Solução em Branco).

Se olharmos no Solution Explorer veremos que foi criada uma solução vazia, então agora clique com o botão direito do mouse e escolha Add... e em seguida New Project.

Crie um projeto do Tipo Console Application e altere a propriedade Name para FirstT4Entity, conforme demonstrado nas Figuras 3 e 4.

Figura 3. Adicionando um projeto na Solução

Figura 4. Adicionando um novo projeto

Agora vá até o Solution Explorer e clique com o botão direito do mouse sobre o projeto Console Application escolha Add... New item. Escolha a opção ADO.NET Entity Data Model e na propriedade Name coloque T4Entity. Veja as Figuras 5 e 6.

Figura 5. Adicionando um Novo Item

Figura 6. Adicionando um Novo Item

Agora você deve selecionar Generate from database e clicar em Next, conforme a Figura 7.

Figura 7. Selecionando Tipo de Data Model

Clique no botão New Connection e configure as informações conforme seu banco de dados, então clique em OK. No textBox coloque T4Entities e marque a opção “Yes, Include de Sensitive data in the connection string.” e clique em Next. Selecione as tabelas desejadas e clique em Finish, conforme os passos das Figuras 8 a 11.

Figura 8. Tela inicial da configuração do banco de dados.

Figura 9. Configurando o Acesso ao Banco

Figura 10. Nomeando seu Contexto

Figura 11. Selecionando as Tabelas.

Agora precisamos adicionar um arquivo T4(.tt) ao nosso projeto, porém não vamos utilizar a forma padrão que seria clicar sobre o projeto e add new item. Vamos adicionar pelo arquivo Edmx, assim algumas funções que precisaríamos implementar já virão prontos, nos poupando tempo. Com o seu Edmx aberto, clique com o botão direito do mouse e acesse a propriedade Add Code Generation Item. E escolha a opção ADO.NET EntityObject Generation e na propriedade Name coloque T4Entity.tt. Veja os passos nas Figuras 12 e 13.

Figura 12. Adicionando um Code Gerneration Item.

Figura 13. Selecionando o Tipo de Template

Quando é realizada dessa forma, a geração do arquivo T4(.tt) é feita pelo Visual Studio, gerando um script para gerar todas as classes do Entity. Porém não é o que queremos. É necessário gerar um CRUD, no entanto, fazendo dessa forma poupa um trabalho desnecessário, que é a de criar toda a Integração do .tt com o nosso Entity. Vamos precisar apagar uma parte do código contido no arquivo .tt. Para isso você deve apagar tudo que estiver entre “[assembly: EdmSchemaAttribute()]” e “<#+//////Declare Template Public Properties.”. Outro detalhe muito importante é que quando você adiciona o arquivo .tt dessa forma ele automaticamente para de gerar as classes do Entity automaticamente, pois ele passa a respeitar o código do arquivo. Por isso, abra o seu edmx e acesse a aba Properties, alterando a propriedade Code Generation Strategy para “Default”. Veja nas Figuras 14 e 15.

Figura 14. Arquivo Template(.tt)

Figura 15. Propriedade do Edmx.

Agora vamos implementar o código no T4 para que nossa classe CRUD seja gerada automaticamente.

Sempre que se trabalha com T4 é aconselhável criar suas classes como partial, assim, se precisar implementar alguma coisa a mais para uma classe específica, é só criar um outro arquivo com partial e não precisa mexer no T4.

Junto as using já existentes no T4 é necessário colocar a FirstT4Entity, System.Linq.Expressions e System.Linq, conforme a Listagem 1.

Listagem 1. Incluindo as Namespaces


  using FirstT4Entity;
  using System.Linq.Expressions;
  using System.Linq; 
  

Depois de já inseridas as namespaces necessárias para o funcionamento da nossa classe, devemos criar a namespace da nossa classe, conforme a Listagem 2. Nesse caso foi colocado o nome de DAO, mas pode ser colocado a namespace desejada.

Listagem 2. Criando a Namespace


  namespace DAO
  {
   
  }
  

Agora vamos implementar o código que irá gerar as classes e as funções Add,Update, Delete, Find e duas assinaturas para o método GetAll do nosso CRUD. Para entendermos melhor vamos fazer isso por parte. Inicialmente é necessário criar um looping para criarmos todas as classes de acordo com nossas entidades. Veja na Listagem 3.

Listagem 3. Inserindo nome da Classe


  <#
  foreach (EntityType entity in GetSourceSchemaTypes<EntityType>()
   .OrderBy(e=>e.Name))
  {
          #>
      <#=Accessibility.ForType(entity)#>   
      <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class 
      <#=code.Escape(entity)#>DAO 
                      {
  }
  <#
  }
  #>

Após a declaração da namespace estamos realizando um foreach de todas as entidades do nosso contexto para gerar a classe DAO de cada um.

  • <#=Accessibility.ForType(entity)#>: esse trecho vai preencher o tipo de acesso da Entidade, ou seja, private, public, sealed, etc;
  • <#=code.SpaceAfter(code.AbstractOption(entity))#>: aqui é preenchido se a entidade for abstract;
  • <#=code.Escape(entity)#>: esse comando traz o nome da entidade.

Repare que sempre que precisamos codificar, é necessário que o código esteja entre os sinas “<#” e “#>”, que é para indicar onde começa e onde termina. O que fica fora destes sinais é apenas texto escrito e será transportado para o arquivo .cs exatamente como está no arquivo .tt.

Logo abaixo realizamos outro foreach para localizar nosso contexto e criar uma instância dele para podemos incluir, alterar e excluir nossas entidades. Veja na Listagem 4.

Listagem 4. Criando o Contexto


  <#
  foreach (EntityContainer container in GetSourceSchemaTypes
  <EntityContainer>())
  {
  #>
      <#=code.Escape(container)#> _entities=
       new <#=code.Escape(container)#>();
  <#
  }
  #>

Agora vamos implementar os métodos Add, Update, Delete, conforme a Listagem 5.

Listagem 5. Implementando os Métodos


  public void Add(<#=code.Escape(entity)#> _ent)
  {
         _entities.AddTo<#=code.Escape(entity)#>(_ent);
         _entities.SaveChanges();
  }
   
  public void Update(<#=code.Escape(entity)#> _ent)
  {
      _entities.ApplyCurrentValues("<#=code.Escape
      (entity)#>", _ent);
      _entities.SaveChanges();            
  }
   
  public void Delete(<#=code.Escape(entity)#> _ent)
  {
         _entities.DeleteObject(_ent);
  }
  

Os três métodos acima são bem simples e bem parecidos. O próximo método a ser implementado é o método Find que exigem um pouco mais de programação. Para implementá-lo é necessário outro foreach para que ele encontre a chave da entidade para utilizarmos como filtro, conforme segue o código da Listagem 6.

Listagem 6. Implementando o Find


  <#
  foreach (EdmProperty property in entity.Properties.Where
   (p => p.DeclaringType == entity && 
    p.TypeUsage.EdmType is PrimitiveType))
         {
               if(ef.IsKey(property))
               { #>
                   public <#=code.Escape(entity)#>     
                   Find(<#=code.Escape(property.TypeUsage)#>   
                   _<#=code.Escape(property)#>)
                 {
                    <#=code.Escape(entity)#> _ent = 
                    new <#=code.Escape(entity)#>();
                    _ent = _entities.<#=code.Escape(entity)
                    #>.Where(e => e.<#=code.Escape
                     (property)#> == 
                      _<#=code.Escape(property)
                      #>).FirstOrDefault();
                       return _ent;
                }
                <#
             }
  }#>

Repare que logo abaixo do foreach utilizamos também um if, que serve para checar se a propriedade em questão é a chave da entidade. Caso seja, ele utiliza essa propriedade como filtro para nosso método Find.

Como último passo para criação do CRUD precisamos implementar duas assinaturas GetAll: uma delas não possuirá parâmetro e a outra receberá uma expressão lambda como parâmetro. Dessa forma, uma assinatura irá retornar um IQueryable contendo todos os registros da sua entidade e a outra retornará um IQueryable levando em consideração a expressão lambda passada como parâmetro. Na Listagem 7 você vê a implementação dos métodos GetAll.

Listagem 7. Implementando os GetAlls


  public IQueryable<<#=code.Escape(entity)#>> GetAll()
  {
         return _entities.<#=code.Escape(entity)#>.Select(e=>e);
  }
   
  public IQueryable<<#=code.Escape(entity)#>
   >    GetWithFilter(Expression<
     Func<<#=code.Escape(entity)
     #>,bool>> where)
  {
     return _entities.<#=code.Escape(entity)#>.Where(where);
  }
  

Agora salve o arquivo .tt e vamos acessar o arquivo T4Entity.cs. Para isso, acesse o solution explorer e expanda o arquivo .tt: dê um duplo clique no arquivo.cs. Lá estará todas as classes referentes a cada entidade com os seus métodos. As Figuras 16 e 17 exibem como seu código deve ficar.

Figura 16. Classe CategoryDAO

Figura 17. Classes DAO como Seus Métodos.

No começo parece meio complexo, mas depois será visível como pode ser útil e ágil a implementação de classes com T4. Além disso, essa classe é reaproveitável para qualquer conexão com o Entity.

Espero que tenham gostado deste artigo e que tenha sido útil a vocês.

Até a próxima!