0

Usando e Entendendo AutoMapper

Willams Sousa
Willams Sousa

Introdução


Existem sistemas feitos em variadas linguagens de programação rodando em ambientes variados. É comum você acessar um aplicativo pelo navegador onde parte dele roda em um mainframe, parte no seu próprio computador, parte em um servidor na nuvem, etc.. Cada uma dessas partes podem necessitar de uma informação que é comum a todas as outras. Essa informação é normalmente representada por um objeto cujo molde é projetado em uma classe.


Uma vez que essa informação vai circular por vários ambientes diferentes, através de vários protocolos diferentes, pode ser necessário ter que converter essa informação em vários formatos. A informação pode passar de json para xml, de xml para txt, de txt para uma url, e por aí vai. Dependendo do meio por onde essa informação é enviada pode ser mais adequado uma forma de representação em detrimento da outra. Esse cenário nos coloca diante de um objeto de destino e um objeto de origem na qual pode ser necessário fazer uma conversão.


Os dados mencionados acima podem ser manipulados e transferidos usando uma versão mais simples de si mesmo na qual podemos chamar de DTO ou "Data Transfer Object" (fique a vontade pra achar uma tradução hehe). Você pode ter uma classe que representa os dados vindos do banco de dados com N propriedades e representar essa informação em um formulário em uma página web com uma representação mais simples com menos propriedades onde duas propriedades originais são combinadas em uma só ou uma propriedade do tipo DateTime é representada por uma do tipo string.


Todo o cenário acima nos convida a usar várias bibliotecas para ajudar no processo de transporte e conversão de dados. No entanto, quando estamos lidando com DTOs podemos usar uma biblioteca chamada AutoMapper.


AutoMapper é uma biblioteca que ajuda a mapear um objeto x para um objeto y. Você pode ler mais a respeito aqui: AutoMapper — AutoMapper documentation


Motivação


Vamos simular um cenário típico. Você tem uma classe que guarda a seguinte informação:


public class CalendarEvent

    {

        public DateTime Date { getset; }

        public string Title { getset; }

    }


Perfeito, você tem um evento que é representado com uma data e um título, algo como:

"Não esquecer do aniversário da mamãe", 05/01/2021 15:27:02


Porém, digamos que você esteja representado isso em um formulário web, talvez seria mais interessante ter uma representação assim:


public class CalendarEventForm

    {

        public DateTime EventDate { getset; }

        public int EventHour { getset; }

        public int EventMinute { getset; }

        public string Title { getset; }

    }


Na qual acrescenta a hora e os minutos.


Seria possível mapear um objeto do tipo CalendarEvent para CalendarEventForm manualmente. Mas para objetos maiores, com 50 propriedades, p.ex., isso seria muito chato de fazer e uma biblioteca que ajude no processo seria bem vinda: eis o AutoMapper.


Como Usar - Tutorial


1) Criando o projeto


Primeiramente crie um projeto no Visual Studio Code e DotNet CLI executando os seguintes comandos:


dotnet new console -n AutoMapperExample

cd AutoMapperExample

code .


Isso vai criar uma aplicação do tipo Console chamada AutoMapperExample e abrir o Visual Studio Code na pasta do projeto. Caso não conseguir executar os comandos é só perguntar, provavelmente é algum path ou ferramenta faltando.


1.1) Baixando o pacote do AutoMapper


Digite o seguinte comando:


dotnet add package AutoMapper


(lembrando que pra rodar o aplicativo bastar dar um "dotnet run" sem aspas)


2) Criando as classes


Agora crie as classes mostradas acima, pode ser no mesmo arquivo da classe Program, isto é, em Program.cs.


2.1) Criando um objeto para ser mapeado


No método Main, crie um objeto do tipo CalendarEvent assim:


 var calendarEvent = new CalendarEvent

            {

                Date = new DateTime(2008121520300),

                Title = "Company Holiday Party"

            };


3) Configurando o AutoMapper


Como já mencionado, nosso interesse é mapear esse objeto para um objeto do tipo CalendarEventForm porque queremos apresentar a hora e o minuto também. Para usar a biblioteca AutoMapper precisamos primeiro configurar. Coloque logo abaixo do código acima o seguinte:



            var configuration = new MapperConfiguration(cfg =>

            {

                cfg.CreateMap<CalendarEventCalendarEventForm>()

                  .ForMember(dest => dest.EventDateopt => opt.MapFrom(src => src.Date.Date))

                  .ForMember(dest => dest.EventHouropt => opt.MapFrom(src => src.Date.Hour))

                  .ForMember(dest => dest.EventMinuteopt => opt.MapFrom(src => src.Date.Minute));

                

            });


Para entender o todo, a ideia geral é a seguinte:


var config = new MapperConfiguration(cfg => cfg.CreateMap<Order, OrderDto>());
var mapper = config.CreateMapper();
// or
var mapper = new Mapper(config);
OrderDto dto = mapper.Map<OrderDto>(order);


Ou seja, você configura o AutoMapper para Order e OrderDto, cria um Mapper e quando precisar de um dto você chama o método Map<OrderDto>(order).


Contudo, em nosso exemplos temos um mapeamento mais sofisticado onde temos que falar pro AutoMapper o que fazer quanto as propriedades Date de uma classe e EventDate, EventHour, EventMinute da outra. Pra isso usamos o método ForMember especificando o destino e o que queremos colocar lá.


Não se preocupe se ficou meio complexo, depois nesse tutorial iremos criar outro exemplo com outras ideias e tudo vai ficar mais fácil de entender.


4) Criando o objeto de destino a partir do objeto de oriem usando o método Map


Uma vez que já configuramos como será feita a conversão, podemos criar um objeto do tipo Mapper e chamar Map para converter de CalendarEvent para CalendarEventForm



var mapper = configuration.CreateMapper();


            CalendarEventForm form = mapper.Map<CalendarEventCalendarEventForm>(calendarEvent);


            Console.WriteLine($"{form.EventDate}");



Ok, agora só compilar. No final do artigo vou deixar um link para o código completo.


Mais Exemplo - Student x StudentViewModel


Pra esse exemplo temos o seguinte cenário: A classe Student terá informações tais como nome, email e endereço. Porém, o endereço será representado pela classe Endereço, só que na classe StudentViewModel o endereço é apenas uma string. Nossa configuração vai colocar nessa string apenas a Cidade e o País separados por uma vírgula. Vamos ver como ficará.


1) Criando as classes


class Student

    {


        public string Name { getset; }

        public string Email { getset; }


        public Adress Adress { getset; }

    }


    class StudentViewModel

    {

        public string Name { getset; }

        public string Email { getset; }


        public string Adress { getset; }

    }


    class Adress

    {

        public string Country { getset; }


        public string City { getset; }

    }


Até aí tranquilo, as classes poderiam ter mais propriedades, mas a ideia é ir direto ao ponto.


2) Criando um objeto do tipo Student


var student = new Student

            {

                Name = "Willams",

                Email = "email@email.com",

                Adress = new Adress

                {

                    Country = "Brasil",

                    City = "Americana"

                }

            };


3) Adicionando esse mapeamento na configuração


var configuration = new MapperConfiguration(cfg =>

            {

                cfg.CreateMap<CalendarEventCalendarEventForm>()

                  .ForMember(dest => dest.EventDateopt => opt.MapFrom(src => src.Date.Date))

                  .ForMember(dest => dest.EventHouropt => opt.MapFrom(src => src.Date.Hour))

                  .ForMember(dest => dest.EventMinuteopt => opt.MapFrom(src => src.Date.Minute));




                cfg.CreateMap<StudentStudentViewModel>()

                .ForMember(dest => dest.Adressopt => opt.MapFrom(src => src.Adress.City + ", " + src.Adress.Country));

            });



Note que eu falo pro AutoMapper pra transformar o endereço em uma string fazendo uma concatenação da cidade com o país. Entenda que você pode fazer qualquer coisa, p.ex.:


cfg.CreateMap<Classe1,Classe2>().ForMember(destino => destino.AlgumaCoisa, opt => opt.MapFrom(origem => origem.AlgumaCoisa.ToString + "suffixo-muito-importante");


O céu é o limite (:


4) Mapeando e vendo o resultado


 StudentViewModel studentViewModel = mapper.Map<StudentStudentViewModel>(student);


            Console.WriteLine($"Name: {studentViewModel.Name}");

            Console.WriteLine($"Email: {studentViewModel.Email}");

            Console.WriteLine($"Adress: {studentViewModel.Adress}");



Considerações Finais


Eu evitei apresentar o AutoMapper em um projeto ASP.NET pra que fique mais fácil isolar o que o AutoMapper está fazendo. Em uma aplicação console teremos apenas o AutoMapper funcionando e sem injeção de dependência nem códigos de inicializaçao de outras bibliotecas.


Apesar disso, C# é uma linguagem razoavelmente complexa e pode ser que você não tenha entendido muitos aspectos do código acima. Sugiro que pesquise a respeito, não deixa nada se tornar uma caixa preta pra você. Com certeza terá tutoriais como esse tentando desmistificar o que você não entendeu.


Espero que o tutorial não tenha ficado muito longo e que tenham aprendido. O código fonte desse código pode ser encontrado aqui:


AutoMapperConsoleExample.cs (github.com)

1
37

Comentários (1)

0
Lucas Camargo

Lucas Camargo

05/01/2021 18:55

Legal, obrigado pelo tutorial.

Tento ser um sujeito legal e gosto de aprender linguagens de programação.

Brasil