AutoMapper Map和Flatten Entity with List

时间:2016-11-28 17:08:29

标签: c# automapper

我有以下数据模型

public class Products
{
    public string Name { get; set; }
    public ICollection<ProductSize> ProductSizes { get; set; }
}

public class ProductSize
{
    public double UnitSize { get; set; }
    public ICollection<ProductPackage> ProductPackages { get; set; }
}

public class ProductPackage
{
    public int ItemsPerPack { get; set; }
    public ICollection<ProductPrice> ProductPrices { get; set; }
}

public class ProductPrice
{
    public double Price{ get; set; }
}

我想把它映射到下面的Dto

public class ProductDto
{
    public name Name{ get; set; }
    public double UnitSize { get; set; }
    public int ItemsPerPack { get; set; }
    public double Price{ get; set; }
}

我已经阅读过使用AutoMapper,但我不确定如何设置配置,因为有4个源映射到一个目的地,全部来自列表。我希望有多个具有相同属性值的项目,这是期望的。我是否需要ForMember&lt;&gt;每个项目的地图?

2 个答案:

答案 0 :(得分:1)

您可以在Custom Type Converter

中执行此操作
Func<Products, IEnumerable<ProductDto>> conversion = product => 
    from size in product.ProductSizes
    from package in size.ProductPackages
    from price in package.ProductPrices
    select new ProductDto {
        Name = product.Name,
        UnitSize = size.UnitSize,
        ItemsPerPack = package.ItemsPerPack,
        Price = price.Price
    };

Mapper.Initialize(c => c.CreateMap<Products, IEnumerable<ProductDto>>()
                        .ConvertUsing(conversion));  


var product = GetProduct(…);
var dtos = Mapper.Map<Products, IEnumerable<ProductDto>>(product);

答案 1 :(得分:0)

斯图尔德的答案很棒。但现在我在想为什么在这一点上甚至依赖AutoMapper。我们可以这样做:

public class Products {
   public string Name { get; set; }
   public ICollection<ProductSize> ProductSizes { get; set; }

   public IList<ProductDto> ConvertTo() {
      var q = from size in ProductSizes
      from package in size.ProductPackages
      from price in package.ProductPrices
      select new ProductDto
      {
         Name = this.Name,
         UnitSize = size.UnitSize,
         ItemsPerPack = package.ItemsPerPack,
         Price = price.Price
      };

      return q.ToList();
   }
}

我将此作为测试运行,没有AutoMapper需要.0000768,而使用AutoMapper需要.0836274:

class Program {
static void Main(string[] args) {
   var c = new ProductPackage
   {
      ProductPrices = new List<ProductPrice> { new ProductPrice() }
   };
   var p = Enumerable.Range( 1, 100000 ).Select(x =>
   new Products
   {
      Name = "Good Product",
      ProductSizes = new List<ProductSize> {
      new ProductSize { Name = "Small", UnitSize = 10, ProductPackages = new List<ProductPackage> { c } } }
   } ).ToList();

   Stopwatch w = new Stopwatch();
   w.Start();
   var dto = p.Select(x => x.ConvertTo());
   Console.WriteLine("Without AutoMapper it took: {0}", w.Elapsed);
   w.Stop();

   DoWithAutoMapper(p);

   Console.Read();
}

private static void DoWithAutoMapper(List<Products> p) {

   Func<Products, IEnumerable<ProductDto>> conversion = product =>
         from size in product.ProductSizes
         from package in size.ProductPackages
         from price in package.ProductPrices
         select new ProductDto
         {
            Name = product.Name,
            UnitSize = size.UnitSize,
            ItemsPerPack = package.ItemsPerPack,
            Price = price.Price
         };

   Mapper.Initialize( c => c.CreateMap<Products, IEnumerable<ProductDto>>()
                              .ConvertUsing( conversion ) );

   Stopwatch w = new Stopwatch();
   w.Start();
   var products = p;
   foreach( var item in p ) {

      var dtos = Mapper.Map<Products, IEnumerable<ProductDto>>( item );
   }
   Console.WriteLine( "Using AutoMapper it took: {0}", w.Elapsed );
   w.Stop();
}

我看到的唯一缺点是产品与ProductDto的耦合。我不确定这是否应该是一个评论。我想这是另一种方法。