AutoMapper - 映射多对多关系

AutoMapper - Map Many-to-Many Relationships

在我的 DAL 中,我有以下建立多对多关系的模型。

public class FamilyMember
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ICollection<FamilyMemberPhone> FamilyMemberPhones { get; set; }
}
public class FamilyMemberPhone
{
    public int FamilyMemberId { get; set; }
    public int PhoneId { get; set; }
    public FamilyMember FamilyMember { get; set; }
    public Phone Phone { get; set; }
}
public class Phone : AuditableEntity
{
    public int Id { get; set; }
    public string PhoneNumber { get; set; }
    public bool IsPreferred { get; set; }
    public ICollection<FamilyMemberPhone> FamilyMemberPhones { get; set; }
}

在我的 DTO 中,我有以下 类

public class FamilyMemberDto 
{
    public int Id { get; set; }
    public int FamilyId { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    public bool IsPrimary { get; set; }
    [Required]
    public List<Phone> FamilyMemberPhones { get; set; }
    public string FullName => $" {FirstName} {LastName}";
}
public class PhoneDto
{
    public int Id { get; set; }
    public string PhoneNumber { get; set; }
    public bool IsPreferred { get; set; }
    public PhoneType PhoneType { get; set; }
}

我的映射配置如下所示:

CreateMap<Dal.Models.Phone, Dto.PhoneDto>().ReverseMap().IgnoreAuditableFields();

CreateMap<Dal.Models.FamilyMember, Dto.FamilyMemberDto>();

CreateMap<Dal.Models.FamilyMemberPhone, Dto.PhoneDto>()
            .ForMember(d => d.Id, opt => opt.MapFrom(s => s.Id))
            .ForMember(d => d.PhoneNumber, opt => opt.MapFrom(s => s.Phone.PhoneNumber))
            .ForMember(d => d.PhoneType, opt => opt.MapFrom(s => s.Phone.PhoneType));

CreateMap<Dto.FamilyMemberDto, Dal.Models.FamilyMember>()
            .AfterMap((s, d) =>
            {
                if (d.FamilyMemberPhones != null)
                    foreach (var fmp in d.FamilyMemberPhones)
                        fmp.Id = s.Id;
            });

CreateMap<Dto.PhoneDto, Dal.Models.FamilyMemberPhone>()
            .ForMember(d => d.PhoneId, opt => opt.MapFrom(s => s.Id));

我的单元测试是这样的:

var member = new Bll.Dto.FamilyMemberDto
        {
            FamilyId = 12,
            FirstName = "Jane",
            LastName = "Doe",
            BirthDate = DateTime.Parse("11-01-1990"),
            Email = "test@test.com",
            FamilyMemberPhones = new List<Bll.Dto.PhoneDto>
            {
                new Bll.Dto.PhoneDto
                {
                    PhoneNumber = "test",
                    IsPreferred = true,
                },
                new Bll.Dto.Phone
                {
                    PhoneNumber = "hello",
                    IsPreferred = false,
                }
            }
        };
        await Manager.Save(member);

当我尝试使用 Mapper.Map<Dal.Models.FamilyMember>(dto)DTO 映射到 Model 时,在 entity.FamilyMemberPhones 对象中,我看到集合中有两个项目。然而,深入挖掘集合,所有 Dal.Models.Phone 属性都是空的。

我做错了什么?

来自您代码的这个区域


CreateMap<Dto.FamilyMemberDto, Dal.Models.FamilyMember>()
            .AfterMap((s, d) =>
            {
                if (d.FamilyMemberPhones != null)
                    foreach (var fmp in d.FamilyMemberPhones)
                        fmp.Id = s.Id;
            });

您正在为在循环中创建的变量赋值。那是 fmp.Id = s.Id; 可能而不是 s.Id = fmp.Id; 甚至其他东西。因为那看起来不像你在那里做任何事情。

@formula12 的回答在我脑海中闪过一个念头。我需要考虑添加到家庭成员的每个 phone 号码。结果,每次我将 FamilyMemberDto 映射到 FamilyMember 时,我还需要考虑地图内部的 Phone 列表。

这是我的新映射配置文件:

CreateMap<Phone, Dto.PhoneDto>().ReverseMap().IgnoreAuditableFields();
        CreateMap<FamilyMember, Dto.FamilyMemberDto>();
        CreateMap<FamilyMemberPhone, Dto.PhoneDto>()
            .ForMember(d => d.Id, opt => opt.MapFrom(s => s.Id))
            .ForMember(d => d.PhoneNumber, opt => opt.MapFrom(s => s.Phone.PhoneNumber))
            .ForMember(d => d.PhoneType, opt => opt.MapFrom(s => s.Phone.PhoneType));
        CreateMap<Dto.FamilyMemberDto, FamilyMember>()
            .AfterMap((s, d) =>
            {
                var memberPhones = new List<FamilyMemberPhone>();                    
                foreach (var fmp in s.FamilyMemberPhones)
                {
                    var phone = new FamilyMemberPhone
                    {
                        Phone = new Phone
                        {
                            Id = fmp.Id,
                            PhoneNumber = fmp.PhoneNumber,
                            PhoneType = fmp.PhoneType
                        }
                    };
                    memberPhones.Add(phone);
                }
                d.FamilyMemberPhones = memberPhones;
            });
        CreateMap<Dto.PhoneDto, FamilyMemberPhone>()
            .ForMember(d => d.PhoneId, opt => opt.MapFrom(s => s.Id));

用例: 假设我的家庭成员在 FaimlyMemberDto.FamilyMemberPhones 中有三 (3) 个项目,这是一个 List<PhoneDto>,在完成映射过程时,我的实体现在在 [=17= 中有 3 FamilyMemberPhone 个对象] 在 FamilyMember 对象中。在每一个里面,现在有一个映射到 PhoneDto.

Phone 对象