从 DTO 自动映射(使用 AutoMapper)到其中具有多对多关系的实体

sky*_*ner 1 c# automapper entity-framework-core .net-core

我遇到的问题反映在以下示例中。我在 BookController 中创建了一个 POST 方法来创建一个 Book 实体:

这是我的代码:

public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
    public virtual ICollection<BookCategory> BookCategories { get; set; }
}

public class BookCategory
{
    public int BookId { get; set; }
    public virtual Book Book { get; set; }
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的 DTO:

public class BookDto
{
    public int BookId { get; set; }
    public string Title { get; set; }

    public ICollection<CategoryDto> Categories { get; set; }
}

public class CategoryDto
{
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

自动映射器配置:

        CreateMap<Book, BookDto>().ReverseMap();
        CreateMap<BookCategory, CategoryDto>()
            .ForMember(d => d.CategoryId, opt => opt.MapFrom(s => s.CategoryId))
            .ForMember(d => d.CategoryName, opt => opt.MapFrom(s => s.Category.CategoryName));
        CreateMap<CategoryDto, BookCategory>().ForMember(d => d.CategoryId, opt => opt.MapFrom(s => s.CategoryId));

        CreateMap<BookDto, Book>().AfterMap((s, d) =>
        {
            foreach (var bookCategory in d.BookCategories)
            {
                bookCategory.BookId = s.BookId;
            }
        });
Run Code Online (Sandbox Code Playgroud)

这是我试图映射到实体的 DTO:

        BookDto model = new BookDto()
        {
            Title = "Test book",
            Categories = new List<CategoryDto>()
            {
                new CategoryDto()
                {
                    CategoryId = 1,
                    CategoryName = "drama"
                }
            },
        };
Run Code Online (Sandbox Code Playgroud)

BookDto 是一本新书,但它指向一个现有的类别。数据库中已有 Category.Id = 1,其中 CategoryName 为“戏剧”。当前的问题在于映射:

    CreateMap<BookDto, Book>().AfterMap((s, d) =>
    {
        foreach (var bookCategory in d.BookCategories)
        {
            bookCategory.BookId = s.BookId;
        }
    });
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

当上面的代码即将执行时,d.BookCategories为null。所以我想知道我的映射出了什么问题?

Iva*_*oev 5

AutoMapper 自动映射具有相同名称的成员。由于Book和中的集合BookDto具有不同的名称 ( BookCategoriesvs Categories),因此必须显式映射它们。您可以在其中一张地图中执行此操作,ReverseMap并将处理相反的情况:

CreateMap<Book, BookDto>()
    .ForMember(d => d.Categories, opt => opt.MapFrom(s => s.BookCategories))
    .ReverseMap()
    .AfterMap((s, d) =>
    {
        foreach (var bookCategory in d.BookCategories)
            bookCategory.BookId = s.BookId;
    });
Run Code Online (Sandbox Code Playgroud)

CategoryDto但由于连接实体仅包含 2 个 id,因此您可以避免从toBookCategory和进行映射AfterMap,并使用简单的 LINQ 投影(“Select”)进行反向映射:

CreateMap<Book, BookDto>()
    .ForMember(d => d.Categories, opt => opt.MapFrom(s => s.BookCategories))
    .ReverseMap()
    .ForMember(d => d.BookCategories, opt => opt.MapFrom(s => s.Categories
        .Select(c => new BookCategory { BookId = s.BookId, CategoryId = c.CategoryId })));
Run Code Online (Sandbox Code Playgroud)