首页 > 解决方案 > .Net Core Automapper 具有多对多关系问题

问题描述

我是 Automapper 的新手,我在映射具有多对多关系的类时遇到问题。我想我需要像嵌套映射这样的东西,但文档对我来说似乎并不清晰。我知道我在 AutoMapper 配置上做错了,但我不知道出了什么问题。

当我将一本新书添加到数据库中时,我想收到有关这本书和编写这本书的作者的信息。(预期的 JSON 结果如下)

我有以下课程:

    public class Book
    {
        public int BookId { get; set; }
        public string Title { get; set; }
        public string ISBN { get; set; }
        public string Category { get; set; }
        public int PublisherId { get; set; }
        public Publisher Publisher { get; set; }
        public ICollection<BookAuthor> BooksAuthors { get; set; }
}

    public class Author
    {
        public int AuthorId { get; set; }
        public string AuthorName { get; set; }
        public string AuthorLastName { get; set; }
        public ICollection<BookAuthor> BooksAuthors { get; set; }
    }

    public class BookAuthor
    {
        public int BookId { get; set; }
        public Book Book { get; set; }

        public int AuthorId { get; set; }
        public Author Author { get; set; }
    }

DTO

    public class BookForNewDto
    {
        public string Title { get; set; }
        public string ISBN { get; set; }
        public string Category { get; set; }
        public int PublisherId { get; set; }
        public ICollection<AuthorForNewBookDto> Authors { get; set; }
    }

    public class AuthorForNewBookDto
    {
        public int AuthorId { get; set; }
    }

BookController (AddBook)

        public async Task<IActionResult> AddBook([FromBody] BookForNewDto bookForNewDto)
        {
            var bookToCreate = _mapper.Map<Book>(bookForNewDto);

            var bookToReturn = _mapper.Map<BookForNewDto>(bookToCreate);

            var bookToAdd = await _context.Books.AddAsync(bookToCreate);

            await _context.SaveChangesAsync();

            var bookIdToAdd = bookToCreate.BookId;
            var authorIdToAdd = bookForNewDto.Authors.Select(aa => aa.AuthorId).ToList();

            foreach (var item in authorIdToAdd)
            {
                var bookAuthorToAdd = new BookAuthor()
                {
                    BookId = bookIdToAdd,
                    AuthorId = item
                };
                var newBookAuthor = await _context.BooksAuthors.AddAsync(bookAuthorToAdd);
                await _context.SaveChangesAsync();
            }

            return Ok(bookToReturn);
        }

AutoMapper Profiler // 我只附上了与添加新书有关的部分。

public class AutoMapping : Profile
    {
        public AutoMapping()
        {
               
            CreateMap<BookForNewDto, Book>();
            CreateMap<Book, BookForNewDto>()
                .ForMember(dto => dto.PublisherId, opt => opt.MapFrom(x => x.PublisherId))
                .ForMember(dto => dto.Authors, c => c.MapFrom(c => c.BooksAuthors));

            CreateMap<BookForNewDto, AuthorForNewBookDto>()
                .ForMember(dto => dto.AuthorId, opt => opt.MapFrom(x => x.Authors.Select(aaa => aaa.AuthorId)));
        }

我的问题是如何配置我的 AutoMapper Profiler 以获得下面的 JSON 结果?我对作者有意见。我仍然得到一个空列表。

{
    "title": "sample title",
    "isbn": "123-41-5-12311",
    "category": "test",
    "publisherId": 1,
    "authors": [
            {
                "authorId": 43
            },
            {
                "authorId": 45
            },
            {
                "authorId": 134
            },
}

标签: c#.net-coremany-to-manyautomapperautomapping

解决方案


您必须记住,自动映射器依赖于属性名称来识别可以完成哪些“自动映射”。如果您希望 Automapper 自动映射它们,它们需要相同。在您使用这行代码的情况下:

var bookToCreate = _mapper.Map<Book>(bookForNewDto);

您正在尝试将BookForNewDto实体映射到Book one。您缺少的是 BookForNewDto 有一个名为Authors的属性,而 Book 有一个名为BooksAuthors的属性。Automapper 永远不会知道 Authors 和 BooksAuthors 是它应该映射的。因此,您需要在 Automapper 配置中使用 1 行代码指定此配置:

CreateMap<BookForNewDto, Book>() (this line is already present)
                    .ForMember(dto=>dto.BooksAuthors, opt => opt.MapFrom(x => x.Authors));

现在,如果您调试代码,您将看到 ICollection BooksAuthors 已从您的 BookForNewDto 映射。

您需要添加的下一个映射也是 AuthorForNewBookDto 和 BookAuthor,因为它们存在于您的 2 个实体中:请记住,如果您不指定它,automapper 会将 null 设置为您的值。

这是最终的自动映射器配置:

CreateMap<BookForNewDto, Book>()
                .ForMember(dto=>dto.BooksAuthors, opt => opt.MapFrom(x => x.Authors));
CreateMap<Book, BookForNewDto>()
                .ForMember(dto => dto.PublisherId, opt => opt.MapFrom(x => x.PublisherId))
                .ForMember(dto => dto.Authors, c => c.MapFrom(c => c.BooksAuthors));

CreateMap<BookForNewDto, AuthorForNewBookDto>()
               .ForMember(dto => dto.AuthorId, opt => opt.MapFrom(x => x.Authors.Select(aaa => aaa.AuthorId)));
CreateMap<AuthorForNewBookDto, BookAuthor>();
CreateMap<BookAuthor, AuthorForNewBookDto>();

推荐阅读