Automapper - mapowanie IEnumerable

0

Cześć, mam problem ze zmapowaniem dwóch obiektów.

        public IEnumerable<DropdownModel> GetAuthorsDropdown()
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Author, DropdownModel>()
                .ForMember(dto => dto.Id, opt => opt.MapFrom(x => x.Id))
                .ForMember(dto => dto.DisplayName, opt => opt.MapFrom(x => (x.FirstName + " " + x.SecondName)));
            });

            var authors = _authorRepository.GetAuthors();

            IEnumerable<DropdownModel> authorsDropdown = _mapper.Map<IEnumerable<Author>, IEnumerable<DropdownModel>>(authors); //tutaj występuje exception

            return authorsDropdown;
        }

Poniżej exception, który otrzymuję:

"Error mapping types. Mapping types: IEnumerable1 -> IEnumerable1\r\nSystem.Collections.Generic.IEnumerable1[[DataAccessLogic.Entities.Author, DataAccessLogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] -> System.Collections.Generic.IEnumerable1Application.Models.DropdownModel, Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"} AutoMapper.AutoMapperMappingException

0

No jak dla mnie to config musi się wykonać przed wstrzyknięciem IMapper do klasy. Czyli przy rejestracji mappera do contenera dependency musisz podać configi

0
szydlak napisał(a):

No jak dla mnie to config musi się wykonać przed wstrzyknięciem IMapper do klasy. Czyli przy rejestracji mappera do contenera dependency musisz podać configi

Startup.cs:

            //Automapper
            var mapperConfig = new MapperConfiguration(mc =>
           {
               mc.AddProfile(new AutoMapping());

           });
            IMapper mapper = mapperConfig.CreateMapper();
            services.AddSingleton(mapper);

AutoMapping.cs

    public class AutoMapping : Profile
    {
        public AutoMapping()
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Author, DropdownModel>()
                .ForMember(dto => dto.Id, opt => opt.MapFrom(x => x.Id))
                .ForMember(dto => dto.DisplayName, opt => opt.MapFrom(x => (x.FirstName + " " + x.SecondName)));
            });
        }
    }

Zmieniłem jak powyżej, ten sam problem.

2

Może spróbuj po prostu dodać
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); zamiast tego co masz teraz w ConfigureServices (edit: tzn. wyrzuć cały ted kod dotyczący automappera dodany wcześniej)

Edit2: a profil chyba tak powinien wyglądać:

public class AutoMapping : Profile
    {
        public AutoMapping()
        {
            CreateMap<Author, DropdownModel>()
                .ForMember(dto => dto.Id, opt => opt.MapFrom(x => x.Id))
                .ForMember(dto => dto.DisplayName, opt => opt.MapFrom(x => (x.FirstName + " " + x.SecondName)));
        }
    }

teraz zapisujesz coś w jakieś zmiennej config, która nie jest wykorzystywana

0

@piotrevic: mam jeszcze inną zagwozdkę, mianowicie, tą klasę:

    public class BookDetailsViewModel
    {
        public string Title { get; set; }
        public string PublishingHouse { get; set; }
        public int NumberOfPages { get; set; }
        public int ISBN { get; set; }
        public IEnumerable<DropdownModel> Authors {get;set;}
    }

chciałbym przekonwertować na:

    public class Book
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public virtual ICollection<BookAuthor> Authors { get; set; }
        public string PublishingHouse { get; set; }
        public int NumberOfPages { get; set; }
        public int ISBN { get; set; }
        public Book()
        {
            Authors = new Collection<BookAuthor>();
        }
    }

Mam jednak problem ze zmapowaniem autorów z modelu DropdownModel do BookAuthor. Zbudowałem mapowanie, ale dostaję ex.

CreateMap<Book, BookDetailsViewModel>()
                .ForMember(dto => dto.Authors.Select(a => a.Id).ToList(), opt => opt.MapFrom(src => src.Authors.Select(a => a.AuthorId).ToList()));

Czy może być to problem typów?

0
Krispekowy napisał(a):

@piotrevic: mam jeszcze inną zagwozdkę, mianowicie, tą klasę:

    public class BookDetailsViewModel
    {
        public string Title { get; set; }
        public string PublishingHouse { get; set; }
        public int NumberOfPages { get; set; }
        public int ISBN { get; set; }
        public IEnumerable<DropdownModel> Authors {get;set;}
    }

chciałbym przekonwertować na:

    public class Book
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public virtual ICollection<BookAuthor> Authors { get; set; }
        public string PublishingHouse { get; set; }
        public int NumberOfPages { get; set; }
        public int ISBN { get; set; }
        public Book()
        {
            Authors = new Collection<BookAuthor>();
        }
    }

Mam jednak problem ze zmapowaniem autorów z modelu DropdownModel do BookAuthor. Zbudowałem mapowanie, ale dostaję ex.

CreateMap<Book, BookDetailsViewModel>()
                .ForMember(dto => dto.Authors.Select(a => a.Id).ToList(), opt => opt.MapFrom(src => src.Authors.Select(a => a.AuthorId).ToList()));

Czy może być to problem typów?

Pierwsza sprawa - jako pierwszy argument metody ForMember powinieneś podać po prostu właściwość do której chcesz mapować, czyli dto.Authors, a nie robić na niej selecta, który wyciąga idki.
Druga sprawa - wyciągasz idki autorów, czyli rozumiem, że chcesz zwrócić listę identyfikatorów, więc typ właściwości Authors w ViewModelu powinien być raczej IEnumerable<int> (lub ...<string>, czy coś innego w zależności czym jest identyfikator), a nie IEnumerable<DropdownModel>.

0

@piotrevic: no ok i moją pierwszą właściwością jest jak widzisz public virtual ICollection<BookAuthor> Authors { get; set; }. No więc ok, to zostawiam w takmi razie bez selecta.
Co do drugiej części - no nie do końca, mam DropdownModel, który ma dwie właściwości: id oraz DisplayName, służy mi to do zbudowania listy rozwijalnej - chcę mapować zaznaczone przez użytkownika idki z listy, dlatego mam tam IEnumerable<DropdownModel>

1

"Pierwszy argument metody ForMember", czyli to co przed pierwszym przecinkiem tutaj:
.ForMember(dto => dto.Authors.Select(a => a.Id).ToList(), opt => opt.MapFrom(src => src.Authors.Select(a => a.AuthorId).ToList()));

Po pierwszej zmianie powinno być:
.ForMember(dto => dto.Authors, opt => opt.MapFrom(src => src.Authors.Select(a => a.AuthorId).ToList()));

A żeby to zawierało listę DropdownModeli to musisz jeszcze zmienić drugi argument, żeby ostatecznie było tak:

.ForMember(
    dto => dto.Authors, 
    opt => opt.MapFrom(
        src => src.Authors.Select(
            a => new DropdownModel() { Id = a.AuthorId, DisplayName = "Jakiś display name" }
        ).ToList()
    )
);

Nie sprawdzałem tego, więc możliwe, że gdzieś się machnąłem, ale o coś takiego chodzi. Za to "Jakiś display name" musisz jeszcze podstawić odpowiednią właściwość z Authora, więc pewnie jakieś a.Name, albo $"{a.FirstName} {a.LastName}"

1 użytkowników online, w tym zalogowanych: 0, gości: 1