如何防止 AutoMapper 覆盖目标对象上的现有值?

Posted

技术标签:

【中文标题】如何防止 AutoMapper 覆盖目标对象上的现有值?【英文标题】:How to prevent AutoMapper from overwriting existing values on destination object? 【发布时间】:2021-12-05 12:28:59 【问题描述】:

我有以下实体和对应的视图模型

public class TopEntity

  public int Id  get; set; 

  public ICollection<BottomEntity> Bottoms  get; set; 


public class BottomEntity

  public int Id  get; set; 

  public int TopId  get; set; 


public class TopEntityViewModel

  public int Id  get; set; 

  public ICollection<BottomEntityViewModel> Bottoms  get; set; 


public class BottomEntityViewModel

  public int Id  get; set; 

我想将TopEntityViewModel 类型的实例映射到TopEntity 类型的实例,而不覆盖BottomEntity.TopId 上可能已经存在的任何值。

我已将 AutoMapper 配置如下:

var mapperConfig = new MapperConfiguration(exp =>

  exp.CreateMap<TopEntity, TopEntityViewModel>();

  exp.CreateMap<BottomEntity, BottomEntityViewModel>();

  exp.CreateMap<TopEntityViewModel, TopEntity>();

  exp.CreateMap<BottomEntityViewModel, BottomEntity>()
    .ForMember(dest => dest.TopId, opts => opts.Ignore());
);

我在映射过程中添加了.ForMember(dest =&gt; dest.TopId, opts =&gt; opts.Ignore()); 以忽略BottomEntity.TopId,认为它应该有助于保留现有值。

我正在像这样映射实例:

mapperConfig.AssertConfigurationIsValid();
            
var mapper = mapperConfig.CreateMapper();

var topEntity = new TopEntity

  Id = 45,
  Bottoms = new List<BottomEntity>
  
    new BottomEntity
    
      Id = 56,
      TopId = 45
    ,
    new BottomEntity
    
      Id = 57,
      TopId = 45
    
  
;

var topEntityVm = new TopEntityViewModel

  Id = 45,
  Bottoms = new List<BottomEntityViewModel>
  
    new BottomEntityViewModel
    
      Id = 56,
    ,
    new BottomEntityViewModel
    
      Id = 57
    
  
;

            
var updatedTopEntity = mapper.Map(topEntityVm, topEntity);

当我访问 updatedTopEntity.Bottoms[&lt;whatever&gt;].TopId 时,它总是设置为 0。 如果我在类上更新我对属性BottomEntity.TopId 的定义以具有像1000 这样的默认值,则在映射后我的所有updatedTopEntity.Bottoms[&lt;whatever&gt;].TopId 都设置为该默认值(示例中为1000)。 我检查了从 mapper.Map 返回的引用是否映射了原始引用并且它们确实如此。

如何防止 AutoMapper 删除现有实例上的任何现有值?

我正在使用 AutoMapper 10.1.1 和 .NET Core 5。You can try a working example here。

【问题讨论】:

你是否也检查过Bottoms是否是同一个集合实例? 研究 AutoMapper.Collection. 【参考方案1】:

AutoMapper 说这个in the documentation:

映射到现有集合时,首先清除目标集合。如果这不是您想要的,请查看 AutoMapper.Collection。

AutoMapper.Collection,根据文档,这样做:

添加将集合映射到现有集合的功能,而无需重新创建集合对象。 将根据用户定义的源集合和目标集合中集合的通用项类型之间的等效性,从预先存在的集合对象中添加/更新/删除项。

安装AutoMapper.Collection后我更新了AutoMapper配置如下:

var mapperConfig = new MapperConfiguration(exp =>
  
    exp.AddCollectionMappers();
                
    exp.CreateMap<TopEntity, TopEntityViewModel>();

    exp.CreateMap<BottomEntity, BottomEntityViewModel>();

    exp.CreateMap<TopEntityViewModel, TopEntity>();

    exp.CreateMap<BottomEntityViewModel, BottomEntity>()
      .ForMember(dest => dest.TopId, opts => opts.Ignore())
      .EqualityComparison((src, dest) => src.Id == dest.Id);
  );

.EqualityComparison((src, dest) =&gt; src.Id == dest.Id); 行添加了 AutoMapper 将使用的相等比较,如下所示:

如果 Id 匹配,则 AutoMapper 会将 BottomEntityViewModel 映射到 BottomEntity 如果 BottomEntityViewModel 存在而 BottomEntity 不存在,则 AutoMapper 将从 BottomEntityViewModel 映射的新 BottomEntity 添加到集合中 如果 BottomEntity 存在而 BottomEntityViewModel 不存在,则 AutoMapper 将从集合中删除 BottomEntity

AutoMapper.Collectionis described here的这种行为 工作示例:https://dotnetfiddle.net/tnaUjY

感谢Lucian Bargaoanu为我指出正确的方向

【讨论】:

以上是关于如何防止 AutoMapper 覆盖目标对象上的现有值?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 AutoMapper 将父引用分配给子属性

csharp Automapper - 多对象源和一个目标

Automapper 自定义解析器源成员到目标对象列表映射问题

automapper

AutoMapper用法

AutoMapper用法