代码之家  ›  专栏  ›  技术社区  ›  SOK

自动映射:一对多->多对多

  •  5
  • SOK  · 技术社区  · 6 年前

    我对汽车制造商还比较陌生。我很难将AutoMapper配置为能够映射 UserViewModel 具有多个 TagViewModel 进入多对多关系( RecipeEntity <-> TagEntity )实体框架核心需要 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; }
    }
    

    测试示例:

    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);
    

    这在一定程度上是可行的——我遇到的问题是 Tag 在…上 UserAndTagEntity 为空。

    1 回复  |  直到 6 年前
        1
  •  11
  •   Ivan Stoev    6 年前

    映射自 UserViewModel 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>();
    

    说明:

    需要行(1),因为目标和源属性 名称 不匹配,所以我们只告诉AutoMapper映射 Tags 的属性 用户视图模型 UserAndTags 的属性 用户实体

    请注意,映射不需要源和目标属性 类型 火柴如果没有(如本例中所示),AutoMapper将使用单独的配置对其进行映射。

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

    在映射(2)中,我们只有一个部分,因此我们使用(3)来指定-即我们映射 标记视图模型 Tag 的属性 UserAndTagEntity 。同样,类型不匹配,因此我们需要 标记视图模型 TagEntity

    尽管如此,最终结果将是 用户实体 具有的实例 用户和标签 集合填充为 UserAndTagEntity 实例具有正确的 标签 所有物然后使用步骤(5)填充 User 这些实例的属性。