【问题标题】:AutoMapper and interface typed collectionsAutoMapper 和接口类型的集合
【发布时间】:2013-05-13 14:34:42
【问题描述】:

我是 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; }
}

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

非常感谢。

【问题讨论】:

    标签: collections interface mapping automapper dto


    【解决方案1】:

    虽然根据原始问题,@Mightymuke 的回答是正确的,但还有其他问题需要考虑。从 OOP 的角度来看,接口描述行为,示例中的 IFood 不是行为。使用基础 Food 类和 build-in inheritance mapping in 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");
            }
        }
    }
    

    【讨论】:

    • 是的,这样更好 - 这样做。
    【解决方案2】:

    这里的问题是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-04-08
    • 1970-01-01
    • 2015-12-07
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 2012-09-02
    • 1970-01-01
    • 2011-04-01
    相关资源
    最近更新 更多