PetaPoco - Como mapear um relacionamento Many-to-Many (simulação de Lazy Load)

Há algum tempo estou utilizando a micro ORM PetaPoco para alguns projetos pessoais, a grande vantagem é o desempenho, liberadade e facilidade de implementação.
Eu poderia utilizar Entity Framework ou NHibernate, que são mais parrudos e completos, e que inclusive uso em outros projetos, mas o objetivo é justamente descomplicar e deixar o funcionamento o mais leve possível.

O objetivo deste artigo é exemplificar de forma simples e tornar fácil o entendimento de algo que garimpei na Internet e vi muitos artigos, bons, ruins, completos, incompletos, outros bem direitos, outros com muitos frufrus.

Vamos exemplificar então, à começar com algumas definições básicas:

  • View - uma view, oras, então temos Título e outras propriedades que a formam.
  • Campo - é um elemento que compõe uma View. 
  • CampoView - agregação de todos os Campos que compõem Views. Uma View exibe para o usuário um Campo para digitação de nome, outro para digitação de Valor e etc.

Fazendo uma analogia para facilitar o entendimento:

  • Pedido de Venda = View.
  • Produto = Campo.
  • Itens do Pedido de Venda = CampoView.

Um mapeamento many-to-many tem a característica de um agregado como coleção, na prática a maneira como isso ocorre é por "lazy load" (ou não) a lista dos agregados é carregada quando solicitada, não quando o objeto é instanciado.
Então em se tratado de consulta a banco de dados pelas classes quando carregamos uma View é feita a consulta apenas na tabela relacionada, quando consultamos os Campos agregados à instância da View é feita uma consulta apenas para isso.

Mão na massa então

(não estou atentando para a definição da classe de forma correta ao PetaPoco)

public class CampoView
{
    public Guid IdView { getset; }

    public Guid IdCampo { getset; }

    [Ignore]
    public Campo Campo { getset; }
}

Veja que a classe CampoView possui a propriedade Campo (1) decorada com um Ignore do PetaPoco.

Dica: Propriedades decoradas com o atributo Ignore não participam das atribuições dinâmicas de campos feitas pelo PetaPoco em Query/Fetch.

public class Campo
{
    public Guid Id { getset; }
    public string Nome { getset; }
    public int Largura { getset; }
}

Nada demais na classe Campo.
Dica: para quem não sabe o PetaPoco trabalha automaticamente com campos CHAR(36) em formato Guid sem precisarmos fazer conversões, quando atribuímos uma string no formato Guid ele já faz as conversões necessárias.

public class View
{
    public Guid Id { getset; }
    public string Titulo { getset; }     [Ignore]     public List<CampoView> Campos     {         get         {             var sql = PetaPoco.Sql.Builder                 .Append("SELECT camposviews.*, campos.*")                 .Append("FROM camposviews, campos")                 .Append("WHERE (campos.Id = camposviews.IdCampo)")                 .Append("  AND camposviews.IdView = @0"new object[] { this.Id });                          var lista = SeuRepositorioPetaPoco.Query<CampoViewCampo>(sql);             return lista.ToList();         }     } }

A classe View é o ponto central do artigo.
Vejam que a propriedade Campos também está decorada com Ignore.

Detalhando a implementação

var sql = PetaPoco.Sql.Builder
   .Append("SELECT camposviews.*, campos.*")
   .Append("FROM camposviews, campos")
   .Append("WHERE (campos.Id = camposviews.IdCampo)")
   .Append("  AND camposviews.IdView = @0"new object[] { this.Id });

Lembrando que estamos contextualizados em uma instância de View, esta é uma simples query com inner join para a tabela de Campos para então montar a relação de Campos desta View, por isso o parâmetro this.Id (da view) para o IdView da tabela de agregação.

A execução desta query irá listar todos os Campos agregados da View em contexto.


var lista = SeuRepositorioPetaPoco.Query<CampoViewCampo>(sql);

Já esta linha fará as atribuições dos campos projetados pela query executada.

Por padrão do PetaPoco a execução desta query irá gerar uma lista de CampoView, a propriedade Campo (1) da classe CampoView irá fazer com que os campos projetados da tabela campos sejam atribuídos como instância automaticamente.


Resumo

  1. Três classes, pai, filho, agregação dos filhos do pai.
  2. Execução da query montando a agregação e atribuindo o resultado gerando instâncias.



Referências:

  • http://www.toptensoftware.com/petapoco/
  • http://blogs.lessthandot.com/index.php/desktopdev/mstech/csharp/petapoco-mapping-related-objects/
  • http://www.toptensoftware.com/Articles/115/PetaPoco-Mapping-One-to-Many-and-Many-to-One-Relationships



Comentários

Postagens mais visitadas deste blog

Selenium + Firefox = The type initializer for 'System.IO.Compression.ZipStorer' threw an exception

Transmissor sem fio bluetooth Tomate MTB-803 e manual

Problema de rolagem de HTML em iframe no iOS