Dapper - Relacionamento um-para-um (Multi-Mapping)


  Neste artigo veremos como implementar o relacionamento um-para-um usando o Dapper e recurso Multi-Mapping.

Como eu já apresentei o Dapper e já escrevi alguns artigos sobre como usar esse recurso na plataforma .NET, para saber detalhes de instalação, configuração e utilização consulte as referências.

Dapper - Definindo um relacionamento um-para-um

A nível de banco de dados em um relacionamento um para um, um registro em uma tabela esta associado a um e apenas um registro em outra tabela.

Tomemos como exemplo o caso onde cada cliente de uma empresa que gerencia vistos para viagens deve possuir um único passaporte. Podemos expressar isso a nível de banco de dados usando duas tabelas Clientes e Passaportes onde cada cliente deve possuir pelo menos um passaporte.

A nível de entidades poderíamos definir as entidades : Cliente e Passaporte e definir propriedades para identificar o cliente e o passaporte e a seguir definir o relacionamento um-para-um entre esses objetos.

Então vamos supor que as entidades foram definidas conforme o código a seguir:

1- Cliente

    public class Cliente
    {
        public int ClienteId { get; set; }
        public string Nome { get; set; }
        public string Email { get; set; }
        public DateTime Nascimento { get; set; }
        public string Sexo { get; set; }
        public Passaporte DadosPassaporte { get; set; }
    }

Aqui representamos a associação entre Cliente e Passaporte definindo a propriedade do tipo Passaporte chamada DadosPassaporte.

2- Passaporte

    public class Passaporte
    {
        public int PassaporteId { get; set; }
        public string PassaporteNumero { get; set; }
        public DateTime PassaporteValidade { get; set; }
    }

Usando a SQL podemos recuperar informações relacionadas entre essas duas tables executando uma consulta para obter todos os dados (consulta JOIN padrão) ou podemos executar várias consultas, uma para obter os dados pai e outra para obter dados relacionados.

Para a maioria dos cenários, a execução de uma consulta JOIN provavelmente é a escolha certa. Cada registro retornado de uma consulta JOIN incluirá dados de vários objetos.

Montando a consulta JOIN SQL básica para este caso teremos :

use VendasDB;
go
SELECT *
FROM Clientes as C
INNER JOIN Passaportes as P ON P.ClienteId = C.ClienteId
ORDER BY C.Nome

O que nos dá o seguinte resultado executado no SQL Server Management Studio:

Ocorre que podemos executar uma consulta no banco de dados e obter como resultado instâncias do tipo Cliente e sua propriedade DadosPassaporte preenchidas com as informações.

O Dapper fornece um recurso chamado Multi mapeamento(Multi-Mapping) para permitir o mapeamento explícito de dados em uma única linha para vários objetos.

Para isso podemos usar métodos de extensão para executar uma consulta e mapear o resultado para uma lista fortemente tipada com relações do tipo um-para-um e um-para-muitos; esses métodos de extensão podem ser chamados de qualquer objeto do tipo IDbConnection.

Em um projeto C# do tipo Console (.NET Core) vamos definir o método GetRelacionamentoUmParaUm() onde após obter a conexão e abrir a conexão, definimos uma consulta SQL e realizamos o mapeamento gerando o relacionamento um-para-um :

 private static IEnumerable<Cliente> GetRelacionamentoUmParaUm()
 {
       string strConexao = ConfigurationManager.ConnectionStrings["conexaoVendas"].ConnectionString;
       SqlConnection conexao = new SqlConnection(strConexao);
       conexao.Open();
       return conexao.Query<Cliente, Passaporte, Cliente>(
              "SELECT * " +
              "FROM Clientes C " +
              "INNER JOIN Passaportes P ON C.ClienteId = P.ClienteId " +
              "ORDER BY C.Nome",
              map: (cliente, passaporte) =>
              {
                  cliente.DadosPassaporte = passaporte;
                  return cliente;
              },
             splitOn: "ClienteId,PassaporteId");
       }

No código acima estamos usando o recurso Multi-Mapping para obter os dados em um relacionamento um-para-um:

Aqui temos :

Agora podemos definir o código do método Main() e tratar a coleção de objetos retornadas

       static void Main(string[] args)
        { 
            IEnumerable<Cliente> clientes = RealacionamentoUmParaUm();
            Console.WriteLine("Cliente \tPassaporte \tValidade");

            foreach (Cliente cli in clientes)
            {
                Console.WriteLine($" { cli.Nome}  \t{cli.DadosPassaporte.PassaporteNumero} " +
                    $"\t{cli.DadosPassaporte.PassaporteValidade}");
            }
            Console.ReadKey();
        }

Note que estamos retornando na propriedade DadosPassaporte os dados relacionados ao cliente.

Executando o projeto iremos obter o resultado abaixo:

Em outro artigo vamos tratar do mapeamento para relacionando do tipo um-para-muitos.

Pegue o projeto completo aqui :  Dapper_Relacionamentos1.zip (sem as referências)

"Vós me chamais Mestre e Senhor, e dizeis bem, porque eu o sou.
Ora, se eu, Senhor e Mestre, vos lavei os pés, vós deveis também lavar os pés uns aos outros.
Porque eu vos dei o exemplo, para que, como eu vos fiz, façais vós também."
João 13:13-15


Referências:


José Carlos Macoratti