AutoMapper,如何在映射对象之间保持引用?

我正在使用AutoMapper将UI模型转换为POCO,后来我使用DataContractSerializer将其序列化为XML,以便保留它们之间的引用。

问题是,在映射时, 这些实体之间的引用会丢失

UI类相互引用,但映射过程为每个引用创建新实例,因此原始关系被破坏:(

让我解释:

我有2个Person类型的实体

Person { List OwnedHouses } 

而这2个对象

拥有的约翰

  • House1

谁也拥有谁

  • House1

当AutoMapper正确映射每个Person时,但它也将House1映射为两个不同的实例!!

所以我有两份House1。 John拥有他的House1(#1)并且Will拥有他的House1(#2)。

他们不再联系了。

有没有办法保持最初存在的关系?

谢谢。

编辑:其实我的拥有是这样的:

文档包含ChildDocuments列表。 每个ChildDocument都有一个Designables列表(Rectangles,Lines,Ellipses …)和一个名为ChildDocumentAdapter的特殊设计,它包含自己的ANOOTHER ChildDocument。 这是麻烦,它可以引用另一个ChildDocument。

图

如果我理解这个问题,你就会执行两个单独的映射操作 – 一个用于John,另一个用于Will。

@Sunny是对的。 AutoMapper不是为此而设计的。 您对Mapper.Map()每次调用通常都独立于其他任何调用。 通过使用HouseListConverter的相同实例,您可以获得在字典中缓存所有映射的房屋的好处。 但您必须全局注册它或将其作为选项传递给您想要组合在一起的映射调用。 这不仅仅是额外的工作,它隐藏了转换器内部非常重要的实现细节。

如果您在一次操作中映射John和Will,通过将它们放入集合中,输出将是您想要的,而无需自定义转换器或解析器。

对于有类似问题的其他人来说,这可能是一个更容易的选择。

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

虽然Automapper的设计并未考虑到这一点,但它足够强大,可以让您使用自定义类型转换器 。 您需要从IList创建自己的转换器到IList ,并使用工厂注入它:

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