Element mapping



  • There are two classes that need to be preserved first in some DTO sites, which completely reproduce the structure of these classes and then re-enter into the baseline:

    public class Element
    {
        public ParentItem Item { get; set; }
    }
    

    public class ParentItem
    {
    public Element Parent { get; set; }
    }

    Method which produces baseline data:

    static Element[] CreateElements()
    {
    var element2 = new Element();
    return new[]
    {
    new Element(new ParentItem(element2)),
    element2,
    new Element()
    };
    }

    Automapper configuration and mapping of established elements:

    Mapper.CreateMap<ElementDto, Element>();
    Mapper.CreateMap<ParentItemDto, ParentItem>();
    Mapper.CreateMap<Element, ElementDto>();
    Mapper.CreateMap<ParentItem, ParentItemDto>();

    var elements = CreateElements();
    var mappedElements = elements
    .Select(_ => Mapper.Map(_, typeof(Element), typeof(ElementDto)))
    .OfType<ElementDto>()
    .ToArray();

    We further check whether the structure of the elements has continued after the mapping:

    foreach (var element in mappedElements)
    {
    Console.WriteLine(mappedElements.Any(e => e?.Item?.Parent == element));
    }

    This code turns out three times. False♪ Which means that for the object element2 from method CreateElements Two copies were made. First copy of the list of elements, second copy ParentItem.Parent

    How do you a mapping to be in? ParentItem.Parent Was there another copy of the element?



  • As it turns out, AutoMapper doesn't know how to break it. Copies of objects will still be created.

    So this kind of relationship will have to be broken by hands. In this case, the following may be made. First, when the mapping doesn't copy the whole chain of elements, it's. Element and him. Item♪ The rest of the chain is copied with preliminary checks for duplication of elements.

    Mapper.CreateMap<Item, ItemDto>()
        .ForMember(_ => _.Element, _ => _.Ignore()); 
    

    Second, we need to remember elements that have already been copied and filled up. Item manually.

    static IEnumerable<ElementDto> MapElements(Element[] elements)
    {
        var elementToDtoMap = new Dictionary<Element, ElementDto>();
    
    foreach (var element in elements)
    {
        MapElement(element, null, elementToDtoMap);
    }
    
    return elementToDtoMap.Select(_ =&gt; _.Value);
    

    }

    static void MapElement(Element element, ItemDto parentItem, Dictionary<Element, ElementDto> elementToDtoMap)
    {
    ElementDto elementDto = null;
    if (elementToDtoMap.TryGetValue(element, out elementDto))
    return;

    elementDto = Mapper.Map&lt;ElementDto&gt;(element);
    elementToDtoMap.Add(element, elementDto);
    
    if (parentItem != null)
    {
        parentItem.Element = elementDto;
    }
    
    if (element.Item != null)
    {
        MapElement(element.Item.Element, elementDto.Item, elementToDtoMap);
    }
    

    }

    Thus, the desired result can be achieved. The code, of course, will depend very much on the case. But the general principle is about that.




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2