AutoMapper:一对多 -> 多对多

SOK*_*SOK 2 c# entity-framework automapper entity-framework-core

我对 AutoMapper 还很陌生。我很难将 AutoMapper 配置为能够将UserViewModel多个映射TagViewModel为多对多关系 ( RecipeEntity <-> TagEntity),这是 Entity Framework Core 所需UserAndTagEntity的连接表。

数据对象:

public class TagEntity
{
    public string Name { get; set; }

    public virtual ICollection<UserAndTagEntity> UserAndTags { get; set; } = new List<UserAndTagEntity>();
}

public class UserEntity
{
    public string Name { get; set; }

    public virtual ICollection<UserAndTagEntity> UserAndTags { get; set; } = new List<UserAndTagEntity>();
}

public class UserAndTagEntity
{
    public int Id { get; set; }
    public virtual UserEntity User { get; set; }
    public virtual TagEntity Tag { get; set; }
}

public class UserViewModel
{
    public string Name { get; set; }

    public IList<TagViewModel> Tags { get; set; }
}

public class TagViewModel
{
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

测试示例:

var config = new MapperConfiguration(cfg => {
    cfg.CreateMap<UserEntity, UserViewModel>()
        .ForMember(
            dto => dto.Tags,
            opt => opt.MapFrom(x => x.UserAndTags.Select(y => y.Tag)));

    cfg.CreateMap<UserViewModel, UserEntity>()
        .ForMember(
            dto => dto.UserAndTags,
            opt => opt.MapFrom(x => x.Tags))
        .AfterMap((model, entity) =>
        {
            foreach (var entityUserAndTag in entity.UserAndTags)
            {
                entityUserAndTag.User = entity;
            }
        });

    cfg.CreateMap<TagViewModel, UserAndTagEntity>();
});

var user = new UserViewModel()
{
    Name = "User",
    Tags = new List<TagViewModel>
    {
        new TagViewModel {Name = "Tag 1"},
        new TagViewModel {Name = "Tag 2"},
        new TagViewModel {Name = "Tag 3"},
        new TagViewModel {Name = "Tag 4"},
    }
};

IMapper mapper = config.CreateMapper();

var map = mapper.Map<UserViewModel, UserEntity>(user);
Run Code Online (Sandbox Code Playgroud)

这部分有效 - 我的问题是TagonUserAndTagEntity为空。

Iva*_*oev 8

UserViewModelto的映射UserEntity可以通过以下配置实现:

CreateMap<UserViewModel, UserEntity>()
    // (1)
    .ForMember(entity => entity.UserAndTags, opt => opt.MapFrom(model => model.Tags))
    // (5)
    .AfterMap((model, entity) =>
    {
        foreach (var entityUserAndTag in entity.UserAndTags)
        {
            entityUserAndTag.User = entity;
        }
    });

// (2)
CreateMap<TagViewModel, UserAndTagEntity>()
    // (3)
    .ForMember(entity => entity.Tag, opt => opt.MapFrom(model => model));

// (4)
CreateMap<TagViewModel, TagEntity>();
Run Code Online (Sandbox Code Playgroud)

解释:

需要线(1),因为目标和源属性名称不匹配,所以我们只是告诉AutoMapper映射Tags的财产UserViewModelUserAndTags的财产UserEntity

请注意,映射不要求源和目标属性类型匹配。如果没有(如本例),AutoMapper 将使用单独的配置映射它们。

在我们的例子中,源属性类型是IList<TagViewModel>,目标属性类型是ICollection<UserAndTagEntity>。忽略集合类型 - AutoMapper 知道如何转换它们。它不知道并且需要指定的是元素类型之间的映射。在我们的例子中,从TagViewModelUserAndTagEntity。因此需要映射(2)。

在映射 (2) 中,我们只有一个部分,因此我们使用 (3) 来指定 - 即我们映射TagViewModel到 的Tag属性UserAndTagEntity。类型再次不匹配,因此我们需要从TagViewModel到的映射(4)TagEntity

所有这些最终结果将是具有正确属性的UserEntity实例的UserAndTags集合。然后使用步骤(5)来填充这些实例的属性。UserAndTagEntityTagUser

  • 嗨,伊万,非常感谢您的宝贵时间和精彩的解释!我正在以你的方式传递一些善业 (2认同)