Ao criar uma aplicação, a recomendação mais ouvida (e que deveria ser a mais seguida) é a separação de responsabilidade entre as camadas do sistema. Existem vários padrões de projetos que auxiliam na implementação deste processo, sendo MVC o mais popular. Hoje há uma infinidade de frameworks baseados neste padrão.
Entretanto em algumas situações apenas ele não garante isso, pode ser necessário ter um desacoplamento maior entre as camadas. Para facilitar este processo, temos o AutoMapper.
AutoMapper
O AutoMapper é uma biblioteca open-source criada por Jimmy Bogard para resolver um problema enganosamente complexo, que é o mapeamento de um objeto para outro. Este tipo de tarefa geralmente é chata e tediosa, então esta pequena biblioteca foi criada para resolver esta situação de forma simples.
Curso C# (C Sharp) - ASP.NET MVC
Conhecer o cursoMapeando uma Model para uma ViewModel
O AutoMapper é mais utilizado em aplicações ASP.NET MVC, principalmente quando esta aplicação faz uso do padrão MVVM (Model-View-ViewModel), mas como pode ser utilizado em qualquer tipo de aplicação e para facilitar a explicação, aqui veremos os exemplos do uso desta biblioteca em uma aplicação console simples.
Entretanto, antes de vermos o AutoMapper na prática, vamos compreender o problema que resolve.
Ao implementar padrão MVVM, haverão duas classes com características equivalentes: uma que refletirá o domínio, e.g, uma entidade do Entity Framework; e outra que refletirá a View, a interface da aplicação. Para ilustrar isso, imagine uma entidade Cliente
:
public class Cliente
{
public long Id { get; set; }
public string Nome { get; set; }
public string Sobrenome { get; set; }
public DateTime DataNascimento { get; set; }
public double Renda { get; set; }
public override string ToString()
=> $"{Id} - {Nome} - {Sobrenome} - {DataNascimento} - {Renda}";
}
Na interface de visualização dos clientes, não deve ser exibido a renda. Desta forma, cria-se uma ViewModel com a seguinte estrutura:
public class ClienteListViewModel
{
public long Id { get; set; }
public string Nome { get; set; }
public string Sobrenome { get; set; }
public DateTime DataNascimento { get; set; }
public override string ToString()
=> $"{Id} - {Nome} - {Sobrenome} - {DataNascimento}";
}
Para mapear os dados de Cliente
para ClienteListViewModel
, podemos fazê-lo manualmente da seguinte forma:
static void Main(string[] args)
{
var cliente = new Cliente()
{
Id = 1,
Nome = "Carlos",
Sobrenome = "Silva",
DataNascimento = new DateTime(1980, 03, 12),
Renda = 4012.04
};
var clienteViewModel = new ClienteListViewModel()
{
Id = cliente.Id,
Nome = cliente.Nome,
Sobrenome = cliente.Sobrenome,
DataNascimento = cliente.DataNascimento
};
Console.WriteLine(clienteViewModel);
Console.ReadLine();
}
Algo simples. Agora imagine ter que trabalhar com uma entidade que possui vinte propriedades, caso haja muitos registros, ou mesmo, com várias entidades implementando o padrão MVVM? É possível ver que este tipo de tarefa simples pode se tornar complicado com adição de poucos detalhes.
É para facilitar este tipo de ação que o AutoMapper foi criado.
AutoMapper vem ao resgate
Para utilizar esta biblioteca em um projeto é necessário adicioná-la via NuGet:
dotnet add package AutoMapper
Na sua utilização básica, é necessário criar uma configuração que indica como as classes são mapeadas:
var configuration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Cliente, ClienteListViewModel>();
});
Em CreateMap
deve ser informado a classe de origem dos objetos (Cliente
) e a classe de destino (ClienteListViewModel
). Caso também seja realizado o mapeamento inverso, isso deve ser informado nesta configuração:
var configuration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Cliente, ClienteListViewModel>();
cfg.CreateMap<ClienteListViewModel, Cliente>();
});
A partir da configuração cria-se um objeto Mapper
:
var mapper = configuration.CreateMapper();
Que irá aplicar o mapeamento:
var clienteViewModel = mapper.Map<ClienteListViewModel>(cliente);
Perfis de entidade
Como as ViewModels refletem as interfaces da aplicação, em alguns projetos uma entidade pode gerar várias ViewModels. Para facilitar a organização dos mapeamentos dessas ViewModels, o AutoMapper permite a criação de perfis (Profile
) para uma entidade:
public class ClienteProfile: Profile
{
public ClienteProfile()
{
CreateMap<Cliente, ClienteListViewModel>();
CreateMap<ClienteListViewModel, Cliente>();
}
}
Com isso, na hora de criar a configuração, indica-se o perfil da entidade:
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddProfile<ClienteProfile>();
});
Outra vantagem de se utilizar perfis é que pode ser informado o assembly da aplicação:
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddMaps(typeof(Program).Assembly);
});
E o AutoMapper irá analisa-lo para carregar os perfis definidos no código. Este tipo de recurso é muito útil quando a aplicação define vários perfis de entidade.
Mapeamento customizado
Caso ambos os objetos possuam propriedades com os mesmos nomes, como no nosso exemplo até o momento, o mapeamento do AutoMapper é automático, mas pode haver situações onde isso não ocorre.
Por exemplo, vamos modificar a nossa classe ClienteListViewModel
para o código abaixo:
public class ClienteListViewModel
{
public long Id { get; set; }
public string NomeCompleto { get; set; }
public DateTime DataNascimento { get; set; }
public override string ToString()
=> $"{Id} - {NomeCompleto} - {DataNascimento}";
}
Isso não irá gerar erro no nosso projeto, mas a biblioteca não saberá mapear o valor de NomeCompleto
, assim esta propriedade não receberá nenhum dado.
Então é necessário informar como essa propriedade deve ser mapeada:
CreateMap<Cliente, ClienteListViewModel>()
.ForMember(dst => dst.NomeCompleto,
map => map.MapFrom(src => $"{src.Nome} {src.Sobrenome}"));
Acima estamos dizendo que a propriedade NomeCompleto
em ClienteListViewModel
deve ser mapeada para os valores de Nome
e Sobrenome
de Cliente
.
Curso C# (C Sharp) - Introdução ao ASP.NET Core
Conhecer o cursoConclusão
O uso básico da biblioteca AutoMapper é muito simples, o que facilita a adoção do padrão MVVM. Além disso, mesmo sendo pequena, possui muitos recursos, que não foram abordados por completo aqui.
Existem outras bibliotecas que realizam este tipo de procedimento, mas caso necessite fazer este tipo de mapeamento no seu projeto, ou esteja pensando em desacoplar as camadas da sua aplicação, o AutoMapper é uma ótima pedida.
Por hoje é só! Até a próxima :)