AutoMapper, how to keep links between matching objects?

I use AutoMapper to convert the user interface model to POCOs, which I later serialize to XML using the DataContractSerializer to keep the links between them.

The problem is that when matching links between these objects are lost .

The user interface classes reference each other, but the mapping process creates new instances for each link, so the original relationships are broken: (

Let me explain:

I have 2 objects of type Person

Person { List<House> OwnedHouses } 

And these 2 objects

John who owns

  • House number 1

Will who also owns

  • House number 1

When AutoMapper correctly displays each person, but when it also displays House1 as two different instances!

So, I have two copies of House1. John owns his House1 (No. 1), and Will owns his House1 (No. 2).

They are no longer connected.

Is there a way to keep the relationship that originally existed?

Thanks.

EDITED: Actually, I have the following:

The document contains a list of ChildDocuments. Each ChildDocument has a list of Designables (Rectangles, Lines, Ellipses ...) and a special design called the ChildDocumentAdapter, which contains the OTHER ChildDocument itself. This is a problem; it may refer to another ChildDocument.

The diagram

+5
source share
2 answers

If I understand the question, you are doing two separate display operations — one for John and one for Will.

@ Sunni is right. AutoMapper is not intended for this. Each call you make in Mapper.Map() is usually independent of the other. Using the same instance of HouseListConverter, you get the advantage of caching all displayed houses in the dictionary. But you need to either register it globally, or pass it as an option for the matching calls that you want to group. This is not just additional work, it hides a very important implementation detail inside the converter.

If you match both John and Will in one operation, putting them in a collection, the result will be what you want, without the need for a custom converter or converter.

This may be a simpler alternative for other people with a similar problem.

 public void MapListOfPeopleWithSameHouse() { Mapper.CreateMap<Person, PersonDTO>(); Mapper.CreateMap<House, HouseDTO>(); var people = new List<Person>(); var house = new House() { Address = "123 Main" }; people.Add(new Person() { Name = "John", Houses = new List<House>() { house } }); people.Add(new Person() { Name = "Will", Houses = new List<House>() { house } }); var peopleDTO = Mapper.Map<List<PersonDTO>>(people); Assert.IsNotNull(peopleDTO[0].Houses); Assert.AreSame(peopleDTO[0].Houses[0], peopleDTO[1].Houses[0]); } 
+3
source

Although Automapper is not designed with this in mind, it is powerful enough to allow you to do this using custom type converters . You need to create your own converter from IList<House> to IList<HouseDto> and enter it using factory:

 using System; using System.Collections.Generic; using AutoMapper; using NUnit.Framework; using SharpTestsEx; namespace StackOverflowExample { public class House { public string Address { get; set; } } public class Person { public IList<House> OwnedHouse { get; set; } } public class HouseDto { public string Address { get; set; } } public class PersonDto { public IList<HouseDto> OwnedHouse { get; set; } } [TestFixture] public class AutomapperTest { public interface IHouseListConverter : ITypeConverter<IList<House>, IList<HouseDto>> { } public class HouseListConverter : IHouseListConverter { private readonly IDictionary<House, HouseDto> existingMappings; public HouseListConverter(IDictionary<House, HouseDto> existingMappings) { this.existingMappings = existingMappings; } public IList<HouseDto> Convert(ResolutionContext context) { var houses = context.SourceValue as IList<House>; if (houses == null) { return null; } var dtos = new List<HouseDto>(); foreach (var house in houses) { HouseDto mapped = null; if (existingMappings.ContainsKey(house)) { mapped = existingMappings[house]; } else { mapped = Mapper.Map<HouseDto>(house); existingMappings[house] = mapped; } dtos.Add(mapped); } return dtos; } } public class ConverterFactory { private readonly IHouseListConverter resolver; public ConverterFactory() { resolver = new HouseListConverter(new Dictionary<House, HouseDto>()); } public object Resolve(Type t) { return t == typeof(IHouseListConverter) ? resolver : null; } } [Test] public void CustomResolverTest() { Mapper.CreateMap<House, HouseDto>(); Mapper.CreateMap<IList<House>, IList<HouseDto>>().ConvertUsing<IHouseListConverter>(); Mapper.CreateMap<Person, PersonDto>(); var house = new House {Address = "any"}; var john = new Person {OwnedHouse = new List<House> {house}}; var will = new Person { OwnedHouse = new List<House> { house } }; var converterFactory = new ConverterFactory(); var johnDto = Mapper.Map<PersonDto>(john, o=>o.ConstructServicesUsing(converterFactory.Resolve)); var willDto = Mapper.Map<PersonDto>(will, o=>o.ConstructServicesUsing(converterFactory.Resolve)); johnDto.OwnedHouse[0].Should().Be.SameInstanceAs(willDto.OwnedHouse[0]); johnDto.OwnedHouse[0].Address.Should().Be("any"); } } } 
+2
source

Source: https://habr.com/ru/post/1481904/


All Articles