【问题标题】:Flatten self referencing object in Auto Mapper在 Automapper 中展平自引用对象
【发布时间】:2016-02-19 19:42:38
【问题描述】:

我有一个自引用模型,我想将其转换为平面列表。模型如下所示。

public class Node
{
    public List<Node> Nodes { get; set; }

    public Person Person { get; set; }

    public Language Language { get; set; }
}

public class NodeDTO
{
    public PersonDTO Person { get; set; }

    public LanguageDTO Language { get; set; }
}

public class NodeListDTO
{
    public List<NodeDTO> Nodes { get; set; }
}

我希望层次结构中的所有节点都被展平为我的 DTO 对象中的一个列表。 Auto Mapper 可以做到吗?

我尝试使用自定义值解析器,但我还没有弄清楚如何在值解析器中使用 PersonDTO 和 LanguageDTO 的映射。

【问题讨论】:

  • 这不是将 Node 映射到 DTO。这是关于包装节点的。您可以在此处使用 Automapper。但是您应该手动进行所有映射。此外,您是否要保留每个节点的内部节点列表也不清楚。
  • @SergeyBerezovskiy 您能否更详细地解释一下包装节点的含义?手动,你的意思是我需要为所有模型做一个自定义值解析器吗?不应保留内部节点列表(请参阅更新的问题)
  • 如果您已编辑问题并将List&lt;Node&gt; 替换为List&lt;NodeDTO&gt;,为什么还要解释?你现在有什么映射?你试过了吗?
  • 你能清楚地说明你想转换“什么到什么”吗?

标签: c# automapper


【解决方案1】:

首先,您需要代码来扁平化节点层次结构。 AutoMapper 不会自动执行此操作。我为此使用了以下扩展方法:

public static IEnumerable<T> Flatten<T>(this T root,
   Func<T, IEnumerable<T>> childrenSelector)
{
    if (!typeof(T).IsValueType && root == null)
        throw new ArgumentNullException(nameof(root));

    return Flatten(new[] { root }, childrenSelector);
}

public static IEnumerable<T> Flatten<T>(this IEnumerable<T> source,
    Func<T, IEnumerable<T>> childrenSelector)
{
    if (source == null)
        throw new ArgumentNullException(nameof(source));

    if (childrenSelector == null)
        throw new ArgumentNullException(nameof(childrenSelector));

    return FlattenIterator(source, childrenSelector);
}

private static IEnumerable<T> FlattenIterator<T>(this IEnumerable<T> source,
    Func<T, IEnumerable<T>> childrenSelector)
{
    if (source != null)
    {
        foreach (var item in source)
        {
            yield return item;
            var children = childrenSelector(item);
            if (children != null)
                foreach (var child in FlattenIterator(children, childrenSelector))
                    yield return child;
        }
    }
}

接下来 - 您需要告诉 AutoMapper 如何展平节点层次并将其映射到列表

MapperConfiguration config = new MapperConfiguration(c =>
{
    c.CreateMap<Person, PersonDTO>();
    c.CreateMap<Language, LanguageDTO>();
    c.CreateMap<Node, NodeDTO>();
    c.CreateMap<Node, NodeListDTO>()
        .ForMember(d => d.Nodes, o => o.ResolveUsing(s => s.Flatten(n => n.Nodes)));
});

现在你可以简单地使用

var node = new Node {
    Person = new Person { Id = 1, Name = "Bob" },
    Language = new Language { Id = 10, Code = "en" },
    Nodes = new List<Node> {
            new Node {
            Person = new Person {  Id = 3, Name = "Mike"},
            Language = new Language {  Id = 11, Code = "es"},
            Nodes = new List<Node> {
                    new Node {
                    Person = new Person {  Id = 4, Name = "Alex"},
                    Language = new Language {  Id = 11, Code = "es"}
                }
            }
        },
        new Node {
            Person = new Person {  Id = 5, Name = "Serge"},
            Language = new Language {  Id = 12, Code = "by"}
        }
    }
};

var nodeListDTO = mapper.Map<NodeListDTO>(node);

结果:

{
  "Nodes": [
    {
      "Person": { "Id": 1, "Name": "Bob" },
      "Language": { "Id": 10, "Code": "en" }
    },
    {
      "Person": { "Id": 3, "Name": "Mike" },
      "Language": { "Id": 11, "Code": "es" }
    },
    {
      "Person": { "Id": 4, "Name": "Alex" },
      "Language": { "Id": 11, "Code": "es" }
    },
    {
      "Person": { "Id": 5, "Name": "Serge" },
      "Language": { "Id": 12, "Code": "by" }
    }
  ]
}

【讨论】:

  • 非常抱歉,我更新了我的问题,但无法让您的答案正常工作。我有问题 .ForMember(d => d.Nodes, o => o.ResolveUsing(s => s.Flatten(n => n.Nodes))); n 是 ResolutionResult 类型,因此没有称为 Nodes 的成员。
  • @Abris 很抱歉,我回滚了您的更改。您不应添加使答案无效的修改。 ResolveUsing 有几个重载,其中一个接受 Func&lt;TSource, object 确保您调用的是正确的。
  • 好的,很好,但我的修改是在你回答之前进行的
  • @Abris 在这里没问题,只是为了将来 - 一些用户会大幅修改问题,甚至开始向第一个问题添加新问题。所以最好开始新问题:)
猜你喜欢
  • 2017-06-13
  • 2017-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-28
相关资源
最近更新 更多