Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Erro Mapeamento

Boa noite, criei um exemplo de um setor que tem várias equipes:

    public class Equipe
    {
        [Key]
        public int Id { get; set; }

        public string ?Nome { get; set; }

        public int SetorId { get; set; }

        public virtual Setor ?Setor { get; set; }
    }
    public class Setor
    {
        [Key]
        public int Id { get; set; }

        public string ?Nome { get; set; }

        public int LiderId { get; set; }

        public virtual Voluntario ?Lider { get; set; }

        public virtual ICollection<Equipe> ?Equipes { get; set; }
    }

E tenho o meu controller que lista as equipes:

        [HttpGet]
        public IEnumerable<ExibirEquipeRecord> BuscarEquipes([FromQuery] int skip = 0, [FromQuery] int take = 20)
        {
            IEnumerable<Equipe> equipes = _context.Equipes
                .OrderBy(e => e.Nome).Skip(skip).Take(take).ToList();
            return _mapper.Map<List<ExibirEquipeRecord>>(equipes);
        }

O meu dto que usei o record está assim...

    public record ExibirEquipeRecord(int Id, string Nome, string Setor) { }

Quando vou exibir o postman as equipes, estão vindo dessa maneira...

[
    {
        "id": 5,
        "nome": "Cantina",
        "setor": "Castle.Proxies.SetorProxy"
    },
    {
        "id": 3,
        "nome": "Estacionamento",
        "setor": "Castle.Proxies.SetorProxy"
    },
    {
        "id": 2,
        "nome": "Limpeza",
        "setor": "Castle.Proxies.SetorProxy"
    },
    {
        "id": 4,
        "nome": "Recepção",
        "setor": "Castle.Proxies.SetorProxy"
    },
    {
        "id": 1,
        "nome": "Segurança",
        "setor": "Castle.Proxies.SetorProxy"
    }
]

E o meu Profile está dessa forma...

    public class EquipeProfile : Profile
    {
        public EquipeProfile()
        {
            CreateMap<CadastrarEquipeRecord, Equipe>();
            CreateMap<AtualizarEquipeRecord, Equipe>();
            CreateMap<Equipe, ExibirEquipeRecord>()
                .ForMember(record => record.Setor, options => options.MapFrom(equipe => equipe.Setor.Nome));
        }
    }

Já fiz o debug e vi que o setor de cada equipe está sendo buscado no controller, porém alguma coisa no meu Record está dando errado e o Mapper não está mapeando o nome do setor, pois se eu colocar para exibir o setor, vai entrar em um loop, por isso quero apenas o nome do setor que aquela equipe pertence, alguém saberia me dizer o que pode estar havendo?

2 respostas

Bom dia, Felipe! Tudo certo?

O problema está relacionado ao carregamento das entidades relacionadas, especificamente o Setor da Equipe. Quando você vê "Castle.Proxies.SetorProxy", isso geralmente indica que o Entity Framework está usando proxies para lazy loading, mas a propriedade relacionada não foi carregada.

Para resolver isso, você pode garantir que o Setor seja carregado explicitamente quando você buscar as Equipes. Você pode fazer isso usando o método Include do Entity Framework:

[HttpGet]
public IEnumerable<ExibirEquipeRecord> BuscarEquipes([FromQuery] int skip = 0, [FromQuery] int take = 20)
{
    IEnumerable<Equipe> equipes = _context.Equipes
        .Include(e => e.Setor) // Isso garante que o Setor seja carregado junto com a Equipe
        .OrderBy(e => e.Nome)
        .Skip(skip)
        .Take(take)
        .ToList();

    return _mapper.Map<List<ExibirEquipeRecord>>(equipes);
}

Com essa modificação, o Setor associado a cada Equipe será carregado, e o AutoMapper poderá mapear corretamente o nome do setor para o seu ExibirEquipeRecord.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.
solução!

Bom dia, eu tinha feito isso e não funcionou, mas o Google Gemini me ajudou, mudei a classe record e o profile:

    public record ExibirEquipeRecord(int Id, string Nome, string SetorNome){ }
    public class EquipeProfile : Profile
    {
        public EquipeProfile()
        {
            CreateMap<CadastrarEquipeRecord, Equipe>();
            CreateMap<AtualizarEquipeRecord, Equipe>();
            CreateMap<Equipe, ExibirEquipeRecord>();
        }
    }

O que aconteceu aí foi a mágica da convenção de nomes (o Flattening) do AutoMapper funcionando perfeitamente com o Primary Constructor do C#.

Quando você mudou o nome para SetorNome, o AutoMapper seguiu a lógica:

Viu que a classe Equipe tem uma propriedade chamada Setor.

Viu que dentro de Setor existe uma propriedade chamada Nome.

Combinou as duas (Setor + Nome) e encontrou exatamente o parâmetro SetorNome no construtor do seu record.

Dessa forma, ele consegue resolver tudo sozinho na hora de dar o new no objeto, sem precisar do construtor vazio e sem precisar de configurações manuais no Profile. Seu código ficou muito mais limpo e seguindo as melhores práticas de imutabilidade.