I have two classes:
public class Element
{
public Item Item { get; set; }
}
public class Item
{
public Element Element { get; set; }
}
And I have DTO with same structure for this classes. This method creates source data for mapping:
static Element[] CreateElements()
{
var element2 = new Element();
return new[]
{
new Element(new Item(element2)),
element2,
new Element()
};
}
Then I configuring mapping and map elements:
Mapper.CreateMap<Element, ElementDto>();
Mapper.CreateMap<Item, ItemDto>();
var elements = CreateElements();
var mappedElements = elements
.Select(_ => Mapper.Map(_, typeof(Element), typeof(ElementDto)))
.OfType<ElementDto>()
.ToArray();
After I check result of mapping:
foreach (var element in mappedElements)
{
Console.WriteLine(mappedElements.Any(e => e?.Item?.Element == element));
}
This code shows "False" three times. It follows that the "element2" from "CreateElements" was created two copies.
The same test for the source elements will return "False True False":
foreach (var element in elements)
{
Console.WriteLine(elements.Any(e => e?.Item?.Element == element));
}
As I need to configure the mapping so as not to duplicate elements? Is it possible?
This can be done manually. First, ignore the property Item
to AutoMapper did not copy chain of elements:
Mapper.CreateMap<Item, ItemDto>()
.ForMember(_ => _.Element, _ => _.Ignore());
Secondly, copy the chain manually with a mark viewed items:
static IEnumerable<ElementDto> MapElements(Element[] elements)
{
var elementToDtoMap = new Dictionary<Element, ElementDto>();
foreach (var element in elements)
{
MapElement(element, null, elementToDtoMap);
}
return elementToDtoMap.Select(_ => _.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<ElementDto>(element);
elementToDtoMap.Add(element, elementDto);
if (parentItem != null)
{
parentItem.Element = elementDto;
}
if (element.Item != null)
{
MapElement(element.Item.Element, elementDto.Item, elementToDtoMap);
}
}