6

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

问题来了,当映射时,这些实体之间的引用会丢失

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

让我解释:

我有 2 个 Person 类型的实体

    Person 
    { 
        List<House> OwnedHouses 
    }

而这两个对象

拥有的约翰

  • 房子1

威尔 谁也拥有

  • 房子1

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

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

它们不再链接。

有什么办法可以保持原来存在的关系?

谢谢。

编辑:实际上我所拥有的是:

一个 Document 包含一个 ChildDocument 的列表。每个 ChildDocument 都有一个 Designable 列表(矩形、线条、椭圆……)和一个名为 ChildDocumentAdapter 的特殊设计,它包含自己的另一个 ChildDocument。这就是麻烦,它可以引用另一个ChildDocument。

图表

4

2 回答 2

3

如果我理解这个问题,那么您正在执行两个单独的映射操作 - 一个用于 John,另一个用于 Will。

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

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

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

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]);
}
于 2015-08-13T18:54:04.187 回答
2

虽然 Automapper 的设计并没有考虑到这一点,但它的功能足以让您使用自定义类型转换器来完成它。IList<House>您需要从to创建自己的转换器IList<HouseDto>,并使用工厂注入它:

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");
        }
    }
}  
于 2013-05-21T18:58:13.280 回答