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