O AutoMapper é uma biblioteca pequena e simples construída para resolver um problema aparentemente complexo, que é livrar-se de um código que mapeou um objeto para outro. Este tipo de problema é muito comum e relativamente trabalhoso de resolver, a ferramenta AutoMapper atua nesse cenário de forma simples e elegante.
No artigo anterior foi abordado o padrão View Model no ASP.Net MVC, esse padrão ajuda a organizar o código, pois divide as responsabilidades entre as Models de domínio e as Models que atendem Views, evitando que as Models de domínio sejam alteradas e poluídas com dados desnecessários ao domínio.
A primeira técnica de trabalhar com View Models foi abordada no artigo anterior.
A técnica abordada neste artigo é mais complexa e necessita de um mapeamento entre objetos que é feito com a ajuda da ferramenta AutoMapper.
No livro Padrões de Arquitetura de Aplicações Corporativas, Martin Fowler descreve um padrão base chamado Mapper. O AutoMapper foi desenvolvido por Jimmy Bogard, um dos autores do livro ASP.Net MVC 4 in Action.
Mapeando uma Model de domínio para uma View Model
O cenário deste exemplo é baseado em um sistema muito simples que consulta os dados de um cliente cadastrado e informa um número da sorte gerado randomicamente para este cliente.
Neste cenário possuímos a Model de domínio (cliente).
using System; namespace MvcMapping.Models { public class Cliente { public string Nome { get; set; } public string Sobrenome { get; set; } public DateTime DataNascimento { get; set; } public bool Ativo { get; set; } } }
Note que não existe referência ao dado de número da sorte, pois ele é exibido apenas na View e não é armazenado com os dados de cliente, logo torna-se desnecessário fazer parte da modelagem da Model.
Na técnica apresentada anteriormente a solução seria criar uma View Model com uma propriedade do tipo cliente e complementar com dados adicionais a serem exibidos na View.
Este artigo irá abordar outra técnica que consiste em criar uma classe com a mesma estrutura de cliente e mais os novos dados adicionais, chamaremos ela de ClienteViewModel e estará disponível em uma pasta raiz do projeto MVC chamada ViewModels.
using System; using System.ComponentModel.DataAnnotations; namespace MvcMapping.ViewModels { public class ClienteViewModel { [Required(ErrorMessage = "Preencher campo Nome")] public string Nome { get; set; } public string Sobrenome { get; set; } [Required(ErrorMessage = "Preencher campo Data de Nascimento")] [Display(Name = "Data de Nascimento")] [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:yyyy-MM-dd}")] [DataType(DataType.Date, ErrorMessage="Data em formato inválido")] public DateTime DataNascimento { get; set; } public bool Ativo { get; set; } public int NumeroDaSorte { get; set; } } }
Na classe ClienteViewModel possuímos a mesma estrutura de clientes, mais o dado adicional de número da sorte e os DataAnnotations para validação de formulário.
Até este momento já é possível listar três benefícios imediatos:
- A Model de domínio não precisou ser modificada sem necessidade.
- A Model de domínio não está poluída com DataAnnotations de validação de formulário.
- A manutenção destas classes torna-se muito mais fácil, uma vez que a Model de domínio não está amarrada às características de uma View.
Após a separação das responsabilidades temos uma Model e uma View Model, ambas representando a entidade cliente, agora é necessário mapear um objeto ao outro para que a ClienteController receba a Model cliente e responda para View uma ClienteViewModel (e vice-versa), esse trabalho é executado pelo AutoMapper.
Configurando o AutoMapper no projeto ASP.Net MVC
Primeiramente é necessário configurar as referências das bibliotecas do AutoMapper e isto pode ser feito facilmente com o NuGet
PM> Install-Package AutoMapper
No projeto MVC crie uma pasta vazia chamada Mappers, dentro desta pasta será necessário criar uma classe que servirá de configuração dos profiles de mapeamento (Model > View Model) e (View Model > Model), esses profiles de mapeamento foram separados em dois arquivos, confira como abaixo como criar cada um deles.
Classe AutoMapperConfig
using AutoMapper; namespace MvcMapping.Mappers { public class AutoMapperConfig { public static void RegisterMappings() { Mapper.Initialize(x => { x.AddProfile<DomainToViewModelMappingProfile>(); x.AddProfile<ViewModelToDomainMappingProfile>(); }); } } }
Classe DomainToViewModelMappingProfile
[UPDATE – 12/2015] – Não é mais possível fazer o override do ProfileName nas novas versões do AutoMapper. Basta não sobrescrever esta property
using AutoMapper; using MvcMapping.Models; using MvcMapping.ViewModels; namespace MvcMapping.Mappers { public class DomainToViewModelMappingProfile : Profile { // Não realizar este override na versão 4.x e superiores public override string ProfileName { get { return "DomainToViewModelMappings"; } } protected override void Configure() { Mapper.CreateMap<Cliente, ClienteViewModel>(); } } }
Classe ViewModelToDomainMappingProfile
using AutoMapper; using MvcMapping.Models; using MvcMapping.ViewModels; namespace MvcMapping.Mappers { public class ViewModelToDomainMappingProfile : Profile { // Não realizar este override na versão 4.x e superiores public override string ProfileName { get { return "ViewModelToDomainMappings"; } } protected override void Configure() { Mapper.CreateMap<ClienteViewModel, Cliente>(); } } }
Esta é a estrutura necessária para configurar o AutoMapper de forma a utilizar o mínimo possível de código de mapeamento em outras classes da aplicação.
- AutoMapperConfig > Inicializa os profiles de mapeamento (Model > View Model) e (ViewModel > Model).
- DomainToViewModelMappingProfile > Profile de mapeamento (Model > View Model)
- ViewModelToDomainMappingProfile > Profile de mapeamento (View Model > Model)
Confira como o projeto ficou estruturado
Neste momento resta apenas configurar que a classe AutoMapperConfig seja inicializada junto com a aplicação para registrar os profiles de mapeamento, essa configuração é feita no arquivo Global.asax
using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; using MvcMapping.Mappers; namespace MvcMapping { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AuthConfig.RegisterAuth(); // Configurando o AutoMapper para registrar os profiles // de mapeamento durante a inicialização da aplicação. AutoMapperConfig.RegisterMappings(); } } }
O AutoMapper está devidamente configurado na aplicação, no próximo passo será feita a conversão da Model cliente para a ClienteViewModel na Controller através do mapeamento que foi criado, confira como ficou o código da ClienteController
using System; using System.Web.Mvc; using MvcMapping.Models; using MvcMapping.ViewModels; using AutoMapper; namespace MvcMapping.Controllers { public class ClienteController : Controller { public ActionResult Index() { var rdnGen = new Random(); // Um fake de uma consulta de cliente na base de dados. var cliente = new Cliente { Nome = "Eduardo", Sobrenome = "Pires", DataNascimento = Convert.ToDateTime("24/04/1982"), Ativo = true, }; // Transformando a Model Cliente em ClienteViewModel var clienteView = Mapper.Map<Cliente, ClienteViewModel>(cliente); // Atribuindo valor aos dados adicionais da entidade Cliente clienteView.NumeroDaSorte = rdnGen.Next(1, 100); return View(clienteView); } } }
Note que foi necessário apenas uma linha para transformar a Model Cliente em ClienteViewModel. De forma muito elegante foi criado um objeto do tipo ClienteViewModel já populado com os dados existentes no objeto Cliente.
A partir deste momento o AutoMapper está fazendo o trabalho de mapeamento e a View está recebendo uma View Model compatível com suas necessidades, confira o código da View
@model MvcMapping.ViewModels.ClienteViewModel @{ ViewBag.Title = "Sorte do Dia"; } <hgroup class="title"> <h1>@ViewBag.Title.</h1> </hgroup> <table> <tr> <td> @Html.LabelFor(m => m.Nome) @Html.DisplayFor(m => m.Nome) </td> </tr> <tr> <td> @Html.LabelFor(m => m.Sobrenome) @Html.DisplayFor(m => m.Sobrenome) </td> </tr> <tr> <td> @Html.LabelFor(m => m.DataNascimento) @Html.DisplayFor(m => m.DataNascimento) </td> </tr> <tr> <td> @Html.LabelFor(m => m.Ativo) @Html.DisplayFor(m => m.Ativo) </td> </tr> <tr> <td> @Html.LabelFor(m => m.NumeroDaSorte) @Html.DisplayFor(m => m.NumeroDaSorte) </td> </tr> </table> @section Scripts { @Scripts.Render("~/bundles/jqueryval") }
Para mapear mais Models / View Models basta editar os arquivos DomainToViewModelMappingProfile e ViewModelToDomainMappingProfile com os mapeamentos necessários.
Achou muito trabalhoso ter que montar a estrutura de pasta e os 3 arquivos de mapeamento? Existe uma forma que dispensa toda essa configuração (inclusive inicialização no Global.asax), basta adicionar uma linha a mais em cada momento que houver o mapeamento, confira.
public class ClienteController : Controller { public ActionResult Index() { var rdnGen = new Random(); // Um fake de uma consulta de cliente na base de dados. var cliente = new Cliente { Nome = "Eduardo", Sobrenome = "Pires", DataNascimento = Convert.ToDateTime("24/04/1982"), Ativo = true, }; // Criando o Mapeamento por demanda. Mapper.CreateMap<Cliente, ClienteViewModel>(); // Transformando a Model Cliente em ClienteViewModel var clienteView = Mapper.Map<Cliente, ClienteViewModel>(cliente); // Atribuindo valor aos dados adicionais da entidade Cliente clienteView.NumeroDaSorte = rdnGen.Next(1, 100); return View(clienteView); } }
Apesar de ser mais simples eu pessoalmente não recomendo utilizar o mapeamento desta forma, pois além de somar uma linha a mais em todo momento de executar o mapeamento, o comando de criação de mapeamento não fica centralizado, é difícil ter visão dos mapeamentos já existentes e dificulta também a manutenção.
Resumo
Utilizar o AutoMapper é muito simples conforme foi exemplificado, colabora para adoção do padrão View Model e evita a necessidade de escrever extensos códigos de mapeamento, assim proporcionando mais agilidade no desenvolvimento e facilitando a manutenção, e claro, o código final fica com um aspecto muito mais elegante.
Existem outras ferramentas para mapeamento com a mesma finalidade, a mais popular até o momento é o AutoMapper.
Referências
- http://automapper.org/
- Livro ASP.Net MVC 4 in Action – Página 198, Capítulo. 11.
Nota
“Como mencionado no artigo anterior o padrão View Model está presente no MVC, MVP e MVVM, este artigo aborda a utilização deste padrão para MVC.”
Espero que este artigo ajude a entender o conceito do padrão View Model e o mapeamento de objetos através do AutoMapper.
Feedbacks são sempre muito bem vindos, utilize os comentários abaixo.
AutoMapper é o que há! Bem melhor que ficar mapeando tudo na mão. Ótimo artigo!
Olá Eric,
Realmente é mão na roda! Obrigado pelo feedback!
Abraços.
a Nova versão do AutoMapper não aceita a configuração como descrito. Poderia fazer uma nota da nova versão?
https://github.com/AutoMapper/AutoMapper
Na própria documentação explica como configurar na nova versão.
Olá Eduardo, tudo bem cara?
Ótimo post, parabéns. Apenas fazendo um apêndice no conteúdo:
Quando o mapeamento é simples, ele é perfeito! Porém, quando temos um mapeamento complexo, temos alguns pontos para avaliar. Veja, internamente, o AutoMapper realiza uma querie para cada join definido em nossa querie. Escrevi sobre isto a um tempo atras, veja:
http://rafaelzaccanini.net/2012/02/17/mapeando-simple-objects-e-complex-objects-com-automapper/
Abs
Olá Rafael!
Obrigado pelo feedback e pela contribuição.
Tem razão, inclusive eu participei um tempo da lista de discussão do AutoMapper onde fiquei sabendo desse problema.
Ele também é explicado nesse outro artigo:
http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code
Eu já estou utilizando a versão 3.0 do AutoMapper, de acordo com o Jimmy este problema foi resolvido incorporando as soluções paralelas desse problema na última versão, não sinto mais perda de performance, preciso ainda validar se via profiler ele tem feito menos chamadas:
https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions
Valeu! Abraços.
Vlws DU… estou usado no meu WEB API!!! da hra!!!! abs vei!
Fala Thiago!!!
Bacana cara! Bom desenvolvimento ai!
Se fizer tudo certinho vai ganhar um desse aqui:
https://www.eduardopires.net.br/wp-content/uploads/2013/08/UncleBobApproved.png
🙂
Abraços!
Muito obrigado Eduardo, estou iniciando em MVC4 e este artigo me ajudou bastante! um abraço!
Olá Rafael, obrigado pelo feedback!
Continue acompanhando, tem muita coisa em ASP.Net MVC por vir aqui no blog 🙂
Abraços!
Muito bom, mas teria como eu criar uma view baseada no modelview utilizando o scaffolding ?
Se não for uma View com funcionalidades de CRUD (ligadas a um DbSet da classe context do EF) é possível 🙂
Abraço!
Olá Eduardo Pires, primeiramente parabéns pelo post.
Não tenho muita experiência com projetos MVC e entendo que a Model é um ponto comum entre as camadas “assunto na qual já discuti bastante com outros desenvolvedores”. Porem sempre achei estranho o forte acoplamento dela na aplicação, principalmente em grandes projetos.
Obrigado por me mostrar que não sou um desenvolvedor maluco :-).
Ewerton tudo bem?
Esse assunto é mais denso que parece…
Um site ASP.NET MVC é uma camada, camada de apresentação. Uma grande aplicação possui N camadas, ex se for baseada em DDD essa aplicação possui ao menos 4 camadas (UI [MVC], Domain, Application, Infrastructure) e dentro dessas camadas mais algumas subdivisões.
Falando ainda em DDD a camada de domínio é a que provê os modelos, entidades, objetos de valor etc…
A model do MVC não necessita existir, você precisará representá-las, por isso as ViewModels e o AutoMapper, pois elas espelham os modelos de domínio na UI.
Pensar que a arquitetura de uma aplicação ASP.NET MVC começa e termina no projeto Web é errado, recomendo apenas para projetos bem pequenos.
Te dei mais argumentação agora? 🙂 rsss…
Abraço!
Acredito que 90% delas. rsss
Mais uma vez obrigado por mostrar que sou normal e provar que estou no caminho certo. 🙂
Muito bom Eduardo… valeu…
Desconsidera meu comentario no post sobre Model ViewModel. rsrsrs valeu !
Olá Anderson, muito obrigado!
Tudo bem, vou linkar um post ao outro para facilitar! Valeu!
Eduardo primeiramente parabéns pelo post, mas tenho uma dúvida em relação ao modelo DDD usado com automapper … por exemplo trabalho com padrão repository e meus métodos do repository sempre me retornam um objeto DTO ou View Model …
Mas se eu usar o automapper teria que retornar um objeto model para o controller e fazer o mapeamento … sem contar que não teria como eu usar select new no repository para escapar do lazy loading … gostaria de saber se alguém tem alguma sugestão ou eu estou pensando da maneira errada .
Olá André,
Tem algumas coisas erradas ai.
Se você trabalha com DDD provavelmente tem uma interface do seu repository na camada do seu domínio certo? E para que seu repository retorne uma ViewModel o seu domínio então precisa conhecer essa ViewModel, isso está errado, a ViewModel é uma classe da camada de apresentação, o domínio não deve conhecê-la.
No caso do DDD você tem agregados, ou seja, pode ter classes que são modelagens das quais vc precisa e elas poderão ser transformadas em ViewModels através do AutoMapper.
Você vê algum problema em seguir nessa sugestão?
Abs!
Opa muito obrigado , concordo que dominio nao pode conhecer a apresentação , mas por exemplo em um sistema aqui da empresa uso DTO para transferir esses dados para as classes modelos, mas um dia conversando com um amigo ele me disse que o modelo DDD é muito bom mas se o sistema em si for muito grande pode haver problemas com performance …
Abrs !
Não sei se esta certo mas eu faço assim:
Passo os dados da ViewModel para o controller que por sua vez usa um metodo para fazer o mapeamento do que tem na viewModel para um objeto DTO e passo esse objeto para o repositorio que por sua vez usa um metodo desse objeto DTO para realizar o mapeamento e receber um objeto Modelo aí realizar o “CRUD” não sei se esta certo , se não estiver por favor me ajudem que quero aprender o correto …
Abraços
André,
Tem um passo a mais ai, da ViewModel você já pode transformar direto em Model do domínio na Controller.
A ViewModel é uma espécie de DTO, por que não utiliza apenas ela?
Abs!
Olá André, informação errada, DDD não prejudica em nenhum aspecto a performance do seu sistema.
Nossa muito obrigado Eduardo, realmente me ajudou em muito e mais uma vez meus parabéns pela clareza com que explica.
Abraços.
Olá Pessoal, bom dia!
Como posso fazer para mapear Objetos internos para objetos da ViewModel ?
Exemplo:
O objeto Cotacao [Domínio], estou mapeando para CotacaoViewModel [ViewModel], e este objeto possui Fornecedor [Domínio], porem quero que ele também seja mapeado para FornecedorViewModel.
No final das contas, quero trabalhar com objetos somente da ViewModel entre a controladora e a visão.
Obrigado.
Olá Márcio,
Você pode criar um objeto CotacaoViewModel com uma lista ou um propriedade do tipo FornecedorViewModel.
Abs!
Parabéns Eduardo pelo ótimo artigo. Você tem uma excelente didática.
Obrigado Wesley!
Abs!
Parabéns Eduardo,muito bom o post!!
Muito obrigado Jefferson!
Abs!
Já estava desanimado de mapear aquele monte de ViewModel, show!!!
Seus problemas acabaram! rs.
Abs!
Excelente o o artigo! Parabéns!!!
Muito obrigado Fábio!
Abs!
Em um cenário que eu uso DMX e usando DDD com MVC eu teria 3 “modelo” : ViewModel, Entidade de Domínio e as Entidades do Entity. Como eu usaria o automapper nessa situação? Teria que installar na camada de Apresentação e na Infraestrutura?
Fala Renan,
Nesse caso vc entrou num cenário complexo, pode haver alguns problemas devido a esse modelo.
Eu opto em refazer o modelo usando o EF Power Tools e recriar minhas entidades sem depender do EDMX.
Abs!
Ótimo tutorial, Eduardo!
Mas surgiu uma dúvida quando fui utilizar o AutoMapper com classes que herdem de uma classe base. Por exemplo:
Crio uma classe chamada EntityBase com um Guid e uma Data de Criação.
Faço com que todas as minhas entidades herdem de EntityBase afim de que todas tenham por padrão esses campos e eu não tenha que cria-los manualmente a cada nova entidade.
O AutoMapper não consegue atribuir valores automaticamente a essas propriedades herdadas.
Você tem alguma dica de como fazer isso?
Muito obrigado pelo feedback Fabio,
Esses dois links devem de ajudar:
https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance
http://stackoverflow.com/questions/14705064/mapping-one-source-class-to-multiple-derived-classes-with-automapper
Abs!
Pingback: Você conhece o AutoMapper? | akaMud – Blog
Bom dia Eduardo.
Muito bom o artigo, porém eu tenho uma dúvida.
No seu outro artigo você comenta que podemos criar uma “ViewModel” específica para anteder o nosso negócio.
Ex:
public class CarrinhoComprasViewModel
{
public IEnumerable Produtos { get; set; }
public decimal TotalCarrinho { get; set; }
public string Mensagem { get; set; }
}
Como eu posso utilizar o AutoMapper para realizar esse mapeamento da minha ViewModel (customizada) com a(s) minhas classes na Model (Produtos, ProdutosItens, Etc…) ?
Ou seja, como posso mapear uma ViewModel para duas ou mais Model?
Obrigado.
Fala Wilhelm!
Muito obrigado pelo feedback!
Pode fazer o mapeamento desta forma sim.
Dá uma olhada nessa thread:
http://stackoverflow.com/questions/7580392/how-to-map-multiple-objects-to-one-object-using-automapper-asp-net-mvc-3
Abs!
Fala Eduardo, tudo joia?
Então, entendi o uso do auto mapper graças a você hehe, mas fiquei com uma dúvida:
Como que eu faço o mapeamento de um ViewModel que possui propriedades de dois models e o passo reverso(dos models para o ViewModel)? Estilo Nota e itens da nota.
Desde já agradeço,
Fala Thiago!
Muito obrigado pelo feedback!
Você precisa mapear manualmente (ensinar o automapper a fazer o de > para)
Um ex:
http://stackoverflow.com/questions/7580392/how-to-map-multiple-objects-to-one-object-using-automapper-asp-net-mvc-3
Abs!
Eduardo,
Em uma arquitetura DDD onde eu colocaria o AutoMapper ?
att
No contexto do artigo a o Mapper fica na camada apresentação (MVC). Em alguns casos sua aplicação poderá consumir dados externos na camada de serviço e, nesse caso, é possível usar o AutoMapper para converter da Model “externa” para a sua.
No MVC ou numa camada de Application no DDD
Fala Eduardo,
primeiramente parabéns pelos artigos, você tem me ajudado muito em meu amadurecimento como programador.
Uma duvida, eu costumo utilizar em meus projetos ORM EntityFramework com database-first. Minha dúvida é o seguinte, estou estudando sobre DDD e por usar database-first, eu gero minhas entidades de persistência pelo proprio entity framework (Poco To Entities por exemplo). Utilizar o AutoMaper para mapear meus modelos de domínio para o banco é uma boa pratica? Você recomenda outra maneira?
Muito obrigado! O Automapper serve para mapear qualquer classe em outra!
Fala Eduardo, não conhecia isso. Ficou muito bom usando o AutoMapper agora! Parabens por divulgar conhecimentos.
Muito obrigado Junior!
Muito simples e direta a explicação. Esclareceu perfeitamente uma dúvida que eu tinha! Parabéns pelo post!
Muito obrigado!
Excelente postagem! Depois que li este artigo e um complemento no Stackoverflow, em questão de uma hora já estava com o Autommaper configurado e rodando com um converter customizado em meu projeto.
Como resultado o meu Controller ficou mais limpo mesmo tendo que ensinar o Automapper a converter de uma classe de domínio para Dictionary.
Show de bola 😀
oque você acha de usar o https://www.nuget.org/packages/AutoAutoMapper/
traz beneficios?
Prefiro fazer na mão, mais controle 🙂
Seria possível utilizar o Automapperem aplicações WPF?
É possível sim!
O mais importante neste tipo de abordagem é a clareza e objetividade do artigo.
Os quesitos foram muito bem utilizados, foi muito esclarecedor.
Muito obrigado!
Muito obrigado Rogério!
Cara, sério, escreva um livro!
Muito boa a sua escrita e a forma que passa as informações!
Obrigado pelas dicas e abraços!
Muito obrigado Jean!
Estou pensando nisto 🙂
Então pense com mais afinco!
Realmente seu material é muito bem explicado.
Eduardo,
Tenho seguido alguns dos seus tutoriais e de uns tempos pra cá o AutoMapper começou a reclamar de que o Mapper.Map está obsoleto.
Mapper.Map<IEnumerable,
IEnumerable>(_clientApp.GetAll())
Sabe como resolver para utilizar a nova versão?
João Duarte,
Houve mudança de versão no AutoMapper.
Na classe DomainToViewModelMappingProfile, por exemplo, ele estava reclamando. Tirei o nome da classe Mapper e parou de reclamar.
Antes: Mapper.CreateMap();
Agora:
public class DomainToViewModelMappingProfile : Profile
{
protected override void Configure()
{
CreateMap();
}
}
Na classe de serviço da Application. Ex.: AlunoAppService, o método de adição não mudou…
public void AdicionarAluno(AlunoViewModel alunoViewModel)
{
var aluno = Mapper.Map(alunoViewModel);
// Consome serviço de domínio
_alunoService.AdicionarAluno(aluno);
}
Será que o seu problema também não é na configuração?
ótimo artigo..Parabéns Eduardo.
só fiquei com uma dúvida…
como posso fazer com que as validações criadas no ViewModel funcionem no WindowsForms no C#? pois todos os exemplos que encontrei sobre viewModel sao para ASP.net
Não apenas o Mapper ficou desatualizado (como o Paulo disse, parece que basta chamar CreateMap direto), mas o método sobrescrito Configure() reclama que está obsoleto.
Conhece o ExpressMapper?
Foi criado uma ClienteViewModel para adicionar um campo NumeroDaSorte é o DataAnnotations , este foi o motivo de se utilizar o AutoMapper. Mais o porquê não poderia ser adicionar o campo NumeroDaSorte é DataAnnotations junto com a classe Cliente?
Caro SSouza, o post é antigo mas acho que ainda dá tempo: Termos como Padrões, Boas práticas de programação devem sempre estar presentes na vida do programador, amador ou profissional. Isto leva seu código a se resumir em Organização e (na tão falada pelo autor aqui e na maioria de seus posts) Elegância. Trate seu código com carinho, mantenha-o organizado e elegante, seguindo as boas práticas de programação e os padrões adotados no mundo inteiro. Se você for uma pessoa organizada isto não vai ser problema para você.
Alguem ja teve este erro
Additional information: Expression ‘vm => Convert(vm.Endereco.Id)’ must resolve to top-level member and not any child object’s properties. Use a custom resolver on the child type or the AfterMap option instead.
Eduardo, muito bom o post!
Uma dúvida, tem a possibilidade do autoMapper perder em performance ?? Exemplo em uma conversão de Collection que tem outros objetos ??
Janderson, para resultados complexos existe sim uma perca de performance, uma alternativa é o Dapper, dá uma lida nele que é muito simples de usar também.
Estarei utilizando o AutoMapper no projeto atual e esse post me mostrou que é uma ferramenta bem simples de implementar.
Muito bom!
Parabéns pelos artigos, eu como um iniciante na programação, estou conseguindo acompanhar seus posts facilmente. Ótimas explicações. Parabéns!
Eduardo tenho uma questionamento mais complicado a fazer, tenho a seguinte situação : classe Usuario {
public Nullable usu_tipo { get; set; }
…..
}
Não quero mostrar para o usuário essa informação pois ele não saberá do que se trata quero informar assim na grid esse campo :
1 – Estudante
2 – Avulso
Pesquisei e ví que a melhor maneira seria usar view model olhando esse seu tutorial achei ideal, mais na implementação como associo esse campo no view model ?
Boa noite Eduardo,
Estou a procura de explicações do AutoMapper 5.0.2, você tem alguma explicação, conselhos ou algo que possa me ajudar? Preciso de fazer as configurações mas não estou conseguindo.
Aguardo retorno, abraço.
Atenciosamente,
Bruno Hilário
Bom dia.
Como faço para realizar um mapper de um objeto que contem uma sublista?
ex:
public int Mobilidade { get; set; }
public decimal NotaMobilidade { get; set; }
public List FormacaoModel{ get; set; } //como resolvo esse?
Assumindo que a sua classe chama-se Mobilidade, uma maneira que você pode fazer isso é criando um conversor customizado para mapear a sua lista de FormacaoModel (no caso abaixo chamado de MobilidadeConverter:
// mapeamento da classe usando o conversor customizado
Mapper.CreateMap<Mobilidade, IEnumerable>().ConvertUsing(); // cria a lista de FormacaoModel (dto’s)
Basta agora, criar a classe do seu conversor customizado para mapear a lista (MobilidadeConverter):
class MobilidadeConverter : ITypeConverter<Mobilidade, IEnumerable>
{
public IEnumerable Convert(DbContext context)
{
Mobilidade mobilidade = (Mobilidade)context.SourceValue;
foreach (var dto in mobilidade.FormacaoModel.Select(e => Mapper.Map(e)))
{
Mapper.Map(mobilidade, dto); // mapeia Mobilidade(int) e NotaMobilidade
yield return dto;
}
}
}
Acho que seria isso. Espero ter ajudado. 😀
Mapper.CreateMap<Mobilidade, IEnumerable>().ConvertUsing ** MobilidadeConverter ** ();
Ps: troque os asteriscos ** pelos caracteres menor que e maior que
Alguém pode informar como ficou a versão mais nova do AutoMapper?
Pois a sobrescrita diz que está obsoleto. E os exemplos dados aqui nenhum funcionou.
Valeu galera
Ambos estão dando erro, alguem já conseguiu fazer funcionar na versão mais nova?
public class DomainToViewModelMappingProfile : Profile
{
public override string ProfileName
{
get { return “DomainToViewModelMappings”; }
}
protected override void Configure()
{
Mapper.CreateMap();
}
}
——————
public class ViewModelToDomainMappingProfile : Profile
{
public override string ProfileName
{
get { return “ViewModelToDomainMappings”; }
}
protected override void Configure()
{
Mapper.CreateMap();
}
}
Rogerio, eu estava com o mesmo problema e as soluções postadas aqui também não funcionaram pra mim. Estou usando atualmente a versão 6.0.2 do AutoMapper. Segue abaixo o código que funcionou nesta versão seguindo o padrão mostrado pelo Eduardo no vídeo.
Na classe AutoMapperConfig não mudou nada:
public class AutoMapperConfig
{
public static void RegisterMappings()
{
Mapper.Initialize(x =>
{
x.AddProfile();
x.AddProfile();
});
}
}
As mudanças foram somente nas classes “ViewModelToDomainMappingProfile” e “DomainToViewModelMappingProfile” onde o criação dos mapeamentos são feitos diretamente no construtor das classes. Segue:
public class ViewModelToDomainMappingProfile : Profile
{
public ViewModelToDomainMappingProfile()
{
CreateMap();
CreateMap();
CreateMap();
CreateMap();
}
}
public class DomainToViewModelMappingProfile : Profile
{
public DomainToViewModelMappingProfile()
{
CreateMap();
CreateMap();
CreateMap();
CreateMap();
}
}
Sei que o seu post já é antigo e provavelmente você já deve ter resolvido o seu problema, mas como eu precisei disso agora e demorei muito pra encontrar algo que funcionasse na versão 6.x, resolvi deixar a solução aqui para futuras consultas.
Grande abraço e espero que ajude outras pessoas.
Olá Eduardo,
Mas vamos imaginar que temos um projeto com mais camadas (BLL, DAO etc…) ou utilizando o modelo DDD.
Vc continuaria mantendo a conversão utilizada pelo AutoMapper dentro da Action do Controller? Pois vi no asp.net cast que vc participa, dizendo que não podemos “sujar” o controller com muitas tarefas.
Abraço
Boa Tarde!
Seguir o passo a passo, mas sempre acontece esse erro
“Erro de Servidor no Aplicativo ‘/’.
Não foi possível carregar arquivo ou assembly ‘AutoMapper, Version=5.2.0.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005’ ou uma de suas dependências. A definição do manifesto do assembly localizado não corresponde à referência do assembly. (Exceção de HRESULT: 0x80131040)”
Não conseguir resolver.
Poderia ajudar?
Oi Eduardo, parabéns pelo vídeo!
Conheci o seu trabalho tem pouco tempo e estou lendo vários de seus artigos. No artigo em que você fala sobre o AutoMapper, na classe “DomainToViewModelMappingProfile”, você está utilizando uma ordem diferente de mapeamento da que é utilizada no vídeo:
Vídeo: CreateMap();
Artigo: CreateMap();
Obs: percebi que o AutoMapper não permite mais utilizar o Mapper.CreateMap, apenas o CreateMap. Deu certo no exemplo que fiz.
A função diz “CreateMap”, então a forma de certa seria o exemplo que está no artigo ou não teria problema em escrever assim?
Sou novo na área de desenvolvimento e agradeço muito por compartilhar seu conhecimento.
Não deixou publicar as tag do CreateMap, no caso seria mais ou menos assim:
Vídeo: CreateMap ClienteViewModel, Cliente();
Artigo: CreateMap Cliente, ClienteViewModel();
sem as tags.
Não existe uma forma de deixar a ViewModel mais fácil de ser configurada? Pois dessa forma temos que recriar uma classe que já existe, repetindo código, só pra adicionar um campo, e quando alguma informação for modificada na Model, a ViewModel ficará desatualizada, já que não existe nenhum vinculo explicito entre elas, porque nesse caso não é melhor usar herança ou composição?
Pra quem está procurando como resolver o AutoMap nas versões novas: https://github.com/AutoMapper/AutoMapper/wiki/Configuration
Post muito bem escrito, melhor que a documentação do automapper, venho programando a quase 1 ano e sempre procuro melhorar meu código, vi a necessidade de mappear as classes de uma forma mais automatica, de começo pensei em fazer um módulo para esse mappeamento, porém, com um rápida pequisa achei seu artigo e pronto, agora esta tudo como deveria.
Automapper ajuda o código a ficar limpo, sem necessidade de ficar mappeando classes na mão, parabéns pelo seu artigo.
Excelente artigo. Simples, objetivo e que agrega alto valor para os desenvolvedores. Parabéns!
ALGUEM JA CORRIGIU ESSE ERRO? vs2012 automapper 4.2.1 me dá esse erro, n consigo resolver
Missing type map configuration or unsupported mapping.
Mapping types:
Cliente -> ClienteViewModel
Etecno.Domain.Entities.Cliente -> Etecno.MVC.ViewModels.ClienteViewModel
Destination path:
IEnumerable`1[0]
Source value:
Etecno.Domain.Entities.Cliente
Exelente Post. Claro e objetivo. Muito bem detalhado. Parabéns Eduardo. Gostaria que falasse mais um pouco sobre como utilizar com segurança “.ForMember” e aquelas Options que se usam o source / target. Um grande abraço.