从 DTO 到具有多对多关系的实体的自动映射(使用 AutoMapper)
Auto mapping (with AutoMapper) from DTO to an entity with many-to-many relationship in it
我遇到了以下示例中反映的问题。我在我的 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; }
}
我的 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; }
}
自动映射器配置:
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;
}
});
这是我要映射到实体的 DTO:
BookDto model = new BookDto()
{
Title = "Test book",
Categories = new List<CategoryDto>()
{
new CategoryDto()
{
CategoryId = 1,
CategoryName = "drama"
}
},
};
BookDto 是一本新书,但它指向一个现有类别。在数据库中已经有 Category.Id = 1,"drama" 作为类别名称。当前问题在映射中:
CreateMap<BookDto, Book>().AfterMap((s, d) =>
{
foreach (var bookCategory in d.BookCategories)
{
bookCategory.BookId = s.BookId;
}
});
当上述代码即将执行时,d.BookCategories为空。所以我想知道我的映射有什么问题?
AutoMapper 自动映射具有相同名称的成员。由于 Book
和 BookDto
中的集合具有不同的名称(BookCategories
与 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;
});
但由于连接实体仅包含 2 个 ID,您可以避免从 CategoryDto
到 BookCategory
和 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 })));
我遇到了以下示例中反映的问题。我在我的 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; }
}
我的 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; }
}
自动映射器配置:
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;
}
});
这是我要映射到实体的 DTO:
BookDto model = new BookDto()
{
Title = "Test book",
Categories = new List<CategoryDto>()
{
new CategoryDto()
{
CategoryId = 1,
CategoryName = "drama"
}
},
};
BookDto 是一本新书,但它指向一个现有类别。在数据库中已经有 Category.Id = 1,"drama" 作为类别名称。当前问题在映射中:
CreateMap<BookDto, Book>().AfterMap((s, d) =>
{
foreach (var bookCategory in d.BookCategories)
{
bookCategory.BookId = s.BookId;
}
});
当上述代码即将执行时,d.BookCategories为空。所以我想知道我的映射有什么问题?
AutoMapper 自动映射具有相同名称的成员。由于 Book
和 BookDto
中的集合具有不同的名称(BookCategories
与 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;
});
但由于连接实体仅包含 2 个 ID,您可以避免从 CategoryDto
到 BookCategory
和 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 })));