【问题标题】:Automapper - can it map over only existing properties in source and destination objects?Automapper - 它可以仅映射源和目标对象中的现有属性吗?
【发布时间】:2013-06-13 09:10:13
【问题描述】:

我有一个简单的更新功能:

public void Update(Users user)
{
    tblUserData userData = _context.tblUserDatas.Where(u => u.IDUSER == user.IDUSER).FirstOrDefault();
    if (userData != null)
    {
        Mapper.CreateMap<Users, tblUserData>();
        userData = Mapper.Map<Users, tblUserData>(user);
        _context.SaveChanges()
    }
}

userData 是一个 EF 实体,它的 Entity Key 属性被清空,因为我相信它存在于目标对象中,但不存在于源对象中,因此它被映射为其默认值(对于实体键, 那是空的)

所以,我的问题是 Automapper 是否可以配置为仅尝试映射源对象和目标对象中存在的属性?我希望跳过实体键和导航属性等内容。

【问题讨论】:

    标签: c# asp.net automapper


    【解决方案1】:

    如果需要,您可以像这样明确地将 AutoMapper 告诉 Ignore 某些属性:

    Mapper.CreateMap<Users, tblUserData>()
            .ForMember(dest => dest.Id, opt => opt.Ignore());
    

    这意味着目标对象中的 Id 列将始终保持不变。

    您可以使用Condition 选项指定是否根据逻辑条件的结果应用映射,如下所示:

    Mapper.CreateMap<Users, tblUserData>()
            .ForMember(dest => dest.Id, opt => opt.Condition(src=>src.Id.HasValue));
    

    Mapper.CreateMap<Users, tblUserData>()
            .ForMember(dest => dest.Id, opt => opt.Condition(src=>src.Id != null));
    

    取决于您的具体要求。

    【讨论】:

    • 对,但我必须为我的每个实体显式创建要忽略的属性列表。在我的情况下,对我来说很好的是有一种方法可以关闭“贪婪”映射并让 AutoMapper 比较源对象和目标对象的属性,并且只映射两者中存在的属性。我在文档中没有看到任何这样的选项,所以我想我会在这里问,但我不认为 AutoMapper 会这样。
    • 我了解您要应用的规则:“当我的源属性不为空且我的目标属性不为空时,将源映射到目标”,但我认为不可能将此逻辑全局应用于映射中的每个属性,而无需像我上面所做的那样为每个属性显式创建条件。
    • 我要应用的规则是“当我的源属性存在于目标中时,将源映射到目标,并忽略目标中的所有其他属性”,但我相信你是正确的我需要按照您的指示创建忽略条件。
    【解决方案2】:

    您可以告诉 AutoMapper 忽略您不想像这样映射的字段:

    userData = Mapper.Map<Users, tblUserData>(user).ForMember(m => m.EntityKey, opt => opt.Ignore());
    

    【讨论】:

      【解决方案3】:

      您可以通过创建一个小的扩展方法来忽略目标类型上不存在的所有属性来覆盖此行为。

      public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
      {
          var sourceType = typeof(TSource);
          var destinationType = typeof(TDestination);
          var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType)
              && x.DestinationType.Equals(destinationType));
          foreach (var property in existingMaps.GetUnmappedPropertyNames())
          {
              expression.ForMember(property, opt => opt.Ignore());
          }
          return expression;
      }
      

      那么就可以进行如下映射:

      Mapper.CreateMap<SourceType, DestinationType>().IgnoreAllNonExisting();
      

      还可以根据您的需要自定义此方法,例如,通过专门忽略具有受保护或私有设置器的属性。

      【讨论】:

      【解决方案4】:

      而不是

      userData = _mapper.Map<Users, tblUserData>(user);
      

      使用

       _mapper.Map(user, userData);
      

      前者创建一个新的 userData 对象,其中仅包含用户对象中可用的属性。后者用用户对象中存在的属性覆盖现有的 userData 对象的属性,同时保留其余的。

      【讨论】:

      • 这就是答案!谢谢你:)
      猜你喜欢
      • 2021-02-22
      • 1970-01-01
      • 2018-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-26
      • 2017-06-19
      • 2020-05-04
      相关资源
      最近更新 更多