I'm new to AutoMapper. Sorry if this is too simple.
This is my sample domain:
I have a Basket. It contains a list of Food. Food is either Banana or Pickle.
I have DTOs that mirror each class in the domain. The goal: from a BasketDto, map it and its contents to a Basket.
This is code that fails. After the last line I have a Basket, but it's filled with DTOs instead of regular entities :(
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; }
}
What should I do to Map also the Children using Food as a IList? Mappin interfaces and hierarchies is really complex!
Thanks a lot.
While @Mightymuke's answer is correct based on the original question, there is something else to be considered. From OOP stand point, interfaces describe behavior, and IFood in the example is not a behavior. Using a base Food class, and the build-in inheritance mapping in Automapper, it's more natural:
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");
}
}
}
The problem here is that AutoMapper doesn't know how you want it converted. All the Food items derive from IFood, so the mapping its performing is the simplest (and is correct). You can force the appropriate mapping by creating a TypeConverter - something like this might work:
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;
}
}
This can be configured in your mapping like this:
Mapper.CreateMap<IFood, IFood>().ConvertUsing<FoodConverter>();
Personally I would take it a little further have have the DTO food items derive from:
interface IFoodDto
{
string Name { get; set; }
}
This will make your intention a little clearer to AutoMapper.
Finally, dont forget to call AssertConfigurationIsValid in your mapping.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With