4

我是 AutoMapper 的新手。对不起,如果这太简单了。

这是我的示例域:

我有一个篮子。它包含一个食物列表。食物是香蕉或泡菜。

我有镜像域中每个类的 DTO。目标:从 BasketDto,将其及其内容映射到 Basket。

这是失败的代码。在最后一行之后我有一个篮子,但它充满了 DTO 而不是常规实体:(

class Program
{
    static void Main(string[] args)
    {
        Mapper.CreateMap<BasketDto, Basket>();
        Mapper.CreateMap<PickleDto, Pickle>();
        Mapper.CreateMap<BananaDto, Banana>();

        var dto = new BasketDto
                  {
                      Food = new List<IFood>
                             {
                                 new PickleDto { Name = "BigPickle" },
                                 new BananaDto { Name = "SmallBanana" },
                             }
                  };

        var basketFromDto = Mapper.Map<Basket>(dto);
    }
}

// Domain classes and interfaces --------------

interface IFood
{
    string Name { get; set; }
}

class Banana : IFood
{
    public string Name { get; set; }
}

class Pickle : IFood
{
    public string Name { get; set; }
}

class Basket
{
    public IList<IFood> Food { get; set; }
}

// DTOs -------------

class BasketDto
{
    public IList<IFood> Food { get; set; }
}

class PickleDto : IFood
{
    public string Name { get; set; }
}

class BananaDto : IFood
{
    public string Name { get; set; }
}

我应该怎么做才能映射使用食物作为 IList 的孩子?Mappin 接口和层次结构真的很复杂!

非常感谢。

4

2 回答 2

8

虽然@Mightymuke 的回答基于原始问题是正确的,但还有其他需要考虑的问题。从 OOP 的角度来看,接口描述行为,示例中的 IFood 不是行为。使用基础 Food 类和Automapper 中的内置继承映射,它更自然:

namespace Stackoverflow
{
    public class Food
    {
        public virtual string Name { get; set; }
    }

    public class Banana : Food
    {
    }

    public class Pickle : Food
    {
    }

    public class Basket
    {
        public IList<Food> Food { get; set; }
    }

    public class FoodDto
    {
        public virtual string Name { get; set; }
    }

    public class BananaDto : FoodDto
    {
    }

    public class PickleDto : FoodDto
    {
    }

    public class BasketDto
    {
        public IList<FoodDto> Food { get; set; }
    }

    [TestFixture]
    public class InheritanceMappingTests
    {
        [Test]
        public void Should_map_inherited_classes()
        {
            //arrange
            var basketDto = new BasketDto
                {
                    Food = new List<FoodDto>
                        {
                            new BananaDto {Name = "banana"},
                            new PickleDto {Name = "pickle"}
                        }
                };

            Mapper.CreateMap<FoodDto, Food>()
                  .Include<BananaDto, Banana>()
                  .Include<PickleDto, Pickle>();
            Mapper.CreateMap<BananaDto, Banana>();
            Mapper.CreateMap<PickleDto, Pickle>();
            Mapper.CreateMap<BasketDto, Basket>();

            Mapper.AssertConfigurationIsValid();

            //act
            var basket = Mapper.Map<Basket>(basketDto);

            //assert
            Assert.That(basket.Food[0].GetType() == typeof(Banana));
            Assert.That(basket.Food[0].Name == "banana");
            Assert.That(basket.Food[1].GetType() == typeof(Pickle));
            Assert.That(basket.Food[1].Name == "pickle");
        }
    }
}
于 2013-05-20T13:27:19.980 回答
4

这里的问题是AutoMapper不知道您希望它如何转换。所有Food项目都派生自IFood,因此其执行的映射是最简单的(并且是正确的)。您可以通过创建一个来强制进行适当的映射TypeConverter- 这样的事情可能会起作用:

public class FoodConverter : TypeConverter<IFood, IFood>
{
    protected override IFood ConvertCore(IFood source)
    {
        if (source is PickleDto) return Mapper.Map<Pickle>(source);
        if (source is BananaDto) return Mapper.Map<Banana>(source);
        return null;
    }
}

这可以像这样在您的映射中配置:

Mapper.CreateMap<IFood, IFood>().ConvertUsing<FoodConverter>();

就我个人而言,我会更进一步让 DTO 食品来源于:

interface IFoodDto
{
    string Name { get; set; }
}

这会让你的意图更清楚一点AutoMapper

最后,不要忘记调用AssertConfigurationIsValid您的映射。

于 2013-05-18T21:32:17.240 回答