【问题标题】:Getting Automapper to ignore non-scalar and nav properties in EF让 Automapper 忽略 EF 中的非标量和导航属性
【发布时间】:2012-09-21 10:10:12
【问题描述】:

需要自动映射器将域类型的属性从上下文映射回现有实体(基本上只是更新已更改的字段)。我需要它来忽略导航属性,只映射标量属性。

如果我说 ForMember(o => o.MyNavProperty, opt => opt.Ignore) 我可以让它工作,但我宁愿为我的所有映射提供一个通用方法来告诉它只映射标量和不是导航属性。

尝试遵循 Mauricio 的解决方案:

ASP.net MVC - Should I use AutoMapper from ViewModel to Entity Framework entities?

但我无法让它成功忽略我的导航属性。

这是我的更新版本:

      private static void CreateMapForEF<TDto, TEntity>()
      {
         Mapper.CreateMap<TDto, TEntity>()
    .ForAllMembers(o => o.Condition(ctx =>
                                       {

                                          var members = ctx.Parent.SourceType.GetMember(ctx.MemberName); // get the MemberInfo that we are mapping

                                          if (!members.Any())
                                             return false;

                                          if (members.First().GetCustomAttributes(
                                                typeof (EdmRelationshipNavigationPropertyAttribute), false).Any())
                                             return false;

                                          return members.First().GetCustomAttributes(typeof(EdmScalarPropertyAttribute), false).Any(); // determine if the Member has the EdmScalar attribute set

                                       }));
      }

【问题讨论】:

    标签: c# entity-framework automapper


    【解决方案1】:

    我最近正在研究它。
    您可以使用以下解决方案:

    为导航属性定义一个属性:

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class NavigationPropertyAttribute : Attribute
    {
    } 
    

    用上述属性标记视图模型中的所有导航属性。

    public class TagModel
    {
        public int Id { get; set; }
    
        [Required]
        public string Name { get; set; }
    
        public string Description { get; set; }
    
        [Display(Name = "Image")]
        public string ImagePath { get; set; }
    
        [NavigationProperty]
        public List<ContentModel> Contents { get; set; }
    }
    

    为 AutoMapper 编写一个扩展方法以忽略所有具有NavigationProperty 属性的属性。

    public static IMappingExpression<TSource, TDestination> IgnoreNavigationProperties<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
    {
        var sourceType = typeof(TSource);
    
        foreach (PropertyInfo property in sourceType.GetProperties())
        {
            var isNavProp = property.GetCustomAttributes(typeof(NavigationPropertyAttribute), false).Count() == 1;
            if (isNavProp)
                    expression.ForMember(property.Name, opt => opt.Ignore());
        }
        return expression;
    }
    

    最后你可以按如下方式使用它:

    Mapper.CreateMap<TagModel, Tag>()
            .ForMember(m => m.Id, opt => opt.Condition(m => m.Id > 0))
            .IgnoreNavigationProperties();
    

    【讨论】:

      【解决方案2】:

      我通过向实体添加接口并映射到/从接口来使用显式方法。因此,我没有排除我要明确包含的内容。通过声明部分类来添加接口。

      该接口对我来说是免费的,因为我使用该接口进行解耦、测试存根、模拟等。

      也许只有我一个人,但我不喜欢在 AutoMapper 配置中看到任何忽略。无法证明这一点,但对我来说感觉不对。

      【讨论】:

      • 没有忽略?那么如何处理不允许用户更新的列呢?
      • +1 我同意。这种自动映射有一天会咬你一口,而且很难从代码中看出发生了什么。从接口映射到实体类是保持控制的最佳方式。如果用户不应该更新列,请不要将它们放在界面中,但这也是视图模型/验证要处理的事情。
      • 这更像是一个好奇的事情,看看是否有可能做到这一点,有些人已经发布了像我上面发布的解决方案,但我无法让它们工作。我知道我可以显式设置映射,直到我可以让它工作为止。
      • 嗨 Mark W ...仅供参考 ...它就像我所做的那样工作。让 AutoMapper 做它的名字所暗示的事情。在您的映射对象的代码中定义合同。我的观点是 AutoMapper 文件应该只是映射到这个。否则你会得到部分映射的对象。
      • 贝蒂 - 你不必这样做。这是一件好事,您可以通过代码合同进行映射。如果它不在接口上,则它不是服务的一部分。使用接口类型而不是具体类型来定义对象“是”什么。
      猜你喜欢
      • 1970-01-01
      • 2018-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多