【问题标题】:How do I map a navigation property that is the same type as the class I'm mapping?如何映射与我正在映射的类类型相同的导航属性?
【发布时间】:2021-02-28 17:02:35
【问题描述】:

我正在尝试使用 AutoMapper 将一个类 Function 映射到另一个名为 FunctionDTO 的类。类如下所示:

public class Function
{
     ...
     public int MasterFunctionId { get; set; }
     public Function MasterFunction { get; set; }
     ...
}

public class FunctionDTO
{
     ...
     public int MasterFunctionId { get; set; }
     public FunctionDTO MasterFunction { get; set; }
     ...
}

该映射非常适合MasterFunctionId 等属性,但MasterFunction 始终为空,即使Function 对象在该属性中有值也是如此。

对映射器的调用通过以下方式完成(P.S. 变量 config 被注入到类中):

query.ProjectTo<FunctionModel>(config)

我无法使用以下内容,因为我收到一条错误消息,可能是因为 Mapper 未初始化:

CreateMap<FLHFunction, FunctionModel>()
    .ForMember(f => f.PRNummerMaster, opt => opt.MapFrom(src => Mapper.Map<FLHFunction, FunctionModel>(src)));

有什么方法可以配置映射以使其正常工作?我对上一段代码尝试了类似的解决方案,但我一定遗漏了一些东西。

【问题讨论】:

  • ForMember(f =&gt; f.PRNummerMaster, opt =&gt; opt.MapFrom(src =&gt; src))
  • 已经试过了,属性还是空
  • @Leaky 谢谢你的客气话。本来就是你说的那样,但一直都是空的。我不使用 mapper.Map,我使用带有 EF 查询的 ProjectTo,并传递了一个包含 AutoMapper 配置文件的配置,其中我只有几个 CreateMap 语句。
  • @Corvo,啊,我明白了;这是ProjectTo()。对我来说,它无法处理这样的复合模式仍然听起来很奇怪。我有点懒惰,但也许我会调查一下。 :)
  • 如果没有 AM,您将如何使用 EF linq 查询?

标签: c# entity-framework automapper automapper-7


【解决方案1】:

我研究了一下,不幸的是,这(即自引用、递归映射)似乎不适用于ProjectTo()

几个 GitHub 问题:

https://github.com/AutoMapper/AutoMapper/issues/3195 https://github.com/AutoMapper/AutoMapper/issues/2171 https://github.com/AutoMapper/AutoMapper/issues/1149

JBogard 似乎总是建议为每个级别使用明确命名的分层 DTO。使用这种方法,解决问题非常简单(假设您只想要例如 2 个级别)。

例如:

    public class Function
    {
         public int MasterFunctionId { get; set; }
         public Function MasterFunction { get; set; }
    }

    public class FunctionChildDTO : FunctionDTO {}
    
    public class FunctionDTO
    {
         public int MasterFunctionId { get; set; }
         public FunctionChildDTO MasterFunction { get; set; }
    }

    ...
    
    var config = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Function, FunctionDTO>();
        cfg.CreateMap<Function, FunctionChildDTO>();
        
    });

但希望我错了,有人能够提供适当的解决方案。同时,我将把这个答案留在这里以供参考。

【讨论】:

    【解决方案2】:

    您还需要映射属性类 但由于它引用自身,因此不可能将递归类映射到自身。

        public class Function
    {
         ...
         public int MasterFunctionId { get; set; }
         public ClassA MasterFunction { get; set; }
         ...
    }
    
    public class FunctionDTO
    {
         ...
         public int MasterFunctionId { get; set; }
         public ClassB MasterFunction { get; set; }
         ...
    }
    

    你必须先映射嵌套类 CreateMap()

    然后你可以映射包装类,然后可以使用之前的映射。

    【讨论】:

    • 我明白了,但是在这种情况下 ClassA 和 ClassB 分别是 Function 和 FunctionDTO。我该如何为您的 A 类和 B 类替换它们?
    • 这看起来像是一个设计问题。如果您尝试直接查看它,则可以更容易地弄清楚。 Mapper 只是自动完成手动工作,因此首先您可以手动完成。如果您尝试实例化函数类并将其映射到 FunctionDTO 的 masterfunction 属性,它将进入无限循环。所以你需要改变类的设计。我真的不知道你想通过首先引用类作为它自己的属性来实现什么。
    【解决方案3】:

    据我所知,Automapper 不支持通过投影进行直接自引用映射。文档对此有点模糊,因为您似乎只是缺少递归关联的MaxDepth 配置选项,但我对其进行了相当彻底的测试,虽然它适用于.Map(),但它确实 em> 似乎对 .ProjectTo() 完全有效,即使文档表明 PreserveReferences 不适用于 ProjectTo()MaxDepth 确实如此。

    有效的方法是构建 DTO 以反映层次结构。例如,而不是:

    public class FunctionDTO
    {
         ...
         public int? MasterFunctionId { get; set; }
         public FunctionDTO MasterFunction { get; set; }
    }
    

    对于 1 级自我参考,您可以使用:

    public class FunctionDTO
    {
         ...
         public int? MasterFunctionId { get; set; }
         public MasterFunctionDTO MasterFunction { get; set; }
    }
    
    public class MasterFunctionDTO : FunctionDTO
    {
        public new FunctionDTO MasterFunction 
        { 
            get{ return null;} 
        }
    }  
    

    您的配置将 Function 映射到 FunctionDTO 和 MasterFunctionDTO 的位置​​。 DTO 中的字段基本相同。 MasterFunctionDTO 的 MasterFunction 不会被填充,因此为清楚起见,它的配置选项应设置为 Ignore()

    对于 2 个层次结构:

    public class FunctionDTO
    {
         ...
         public int? MasterFunctionId { get; set; }
         public MasterFunctionDTO MasterFunction { get; set; }
    }
    
    public class MasterFunctionDTO : FunctionDTO
    {
        public new MasterMasterFunctionDTO MasterFunction {get; set;}
    }    
    
    public class MasterMasterFunctionDTO : FunctionDTO
    {
        public new FunctionDTO MasterFunction 
        { 
            get{ return null;} 
        }
    }
    

    将所有 3 个 DTO 映射回 Function 并将最终关卡的“Master”属性设置为 Ignore。 Automapper 可以解析这些引用并对其进行投影。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-04
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 2021-09-16
      • 2021-08-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多