繁体   English   中英

Automapper Unflatten to List

[英]Automapper Unflatten to List

我有需要转换为分层数据的平面表格数据,我正在尝试使用AutoMapper来做到这一点。 这是表格 DTO 源和主/详细目标类的草图。

public class FlatDTO
{
    public string Supplier { get; set; }
    public string OrderNumber { get; set; }
    public string ItemNumber { get; set; }
    public string Amount { get; set; }
}

目标对象如下所示:

public class Order
{
    public string AccountName { get; set; }
    public string OrderNumber { get; set; }
    List<OrderLines> OrderLines { get; set; }
}

public class OrderLines 
{
    public string Item { get; set; }
    public string Amount { get; set; }
}

我的 Automapper 配置文件如下所示:

public class MyAutomapperProfile : Profile
{
    public MyAutomaperProfile ()
    {
        CreateMap<FlatDto, Order>()
          .ForMember(des => des.Account, opt => opt.MapFrom(src => src.Supplier))
          .ReverseMap();

        CreateMap<FlatDto, OrderLines>()
          .ForMember(des => des.Item, opt => opt.MapFrom(src => src.Item))
          .ReverseMap();
    }
}

执行转换的函数:

public Order Transform (List<FlatDto> data)
{
     var output = injectedFromCtorIMapper.Map<Order>(data);
     //throws AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping 
}

示例源数据:

Customer1    1234    Item1   200
Customer1    1234    Item2   500
Customer1    1234    Item3   4000

Target 应该看起来像(实际上不是 Json,但看起来更好):

Order
{ 
    AccountName = "Customer 1",
    OrderNumber = "1234",
    OrderLines [
                   OrderLine
                   {
                      Item: "Item1",
                      Amount: 200
                   },
                   OrderLine
                   {
                      Item: "Item2",
                      Amount: 500
                   }
                   OrderLine,
                   {
                      Item: "Item3",
                      Amount: 4000
                   }
                ]
}

几个问题:

  1. Automapper 是否可以做到这一点,映射配置文件应该是什么样子来支持这种情况?

  2. 如果第 2 行的值为“客户 2”,Automapper 将如何处理? 覆盖第一个值,即胜利中的最后一个?

完成Stefan的编辑; 这是一个示例,说明如果您需要多个 group by ,您可以如何做到这一点。 了解您在问题中的预期结果,您希望对 AcccountName 和 OrderNumber 上的主/明细数据进行分组。 这实际上可以通过映射 IEnumerable 和使用 Automapper 的“ ProjectTo ”扩展(来自命名空间AutoMapper.QueryableExtensions )来实现。 在我的示例数据中,我添加了具有不同 OrderNumber 的一行来说明这一点。

using AutoMapper;
using AutoMapper.QueryableExtensions;
using System.Collections.Generic;
using System.Linq;

namespace AutomapperUnflatten
{
    public class FlatDTO
    {
        public string Supplier { get; set; }
        public string OrderNumber { get; set; }
        public string ItemNumber { get; set; }
        public string Amount { get; set; }
    }

    public class Order
    {
        public string AccountName { get; set; }
        public string OrderNumber { get; set; }
        public List<OrderLines> OrderLines { get; set; }
    }

    public class OrderLines
    {
        public string Item { get; set; }
        public string Amount { get; set; }
    }


    class Program
    {
        static void Main(string[] args)
        {            
            var configuration = new MapperConfiguration(cfg => {
                cfg.CreateMap<IEnumerable<FlatDTO>, Order>()
                     .ForMember(d => d.AccountName, opt => opt.MapFrom(src => src.FirstOrDefault().Supplier))
                     .ForMember(d => d.OrderNumber, opt => opt.MapFrom(src => src.FirstOrDefault().OrderNumber))
                     .ForMember(d => d.OrderLines, opt => opt.MapFrom(src =>
                         src.Select(s => new OrderLines() { Item = s.ItemNumber, Amount = s.Amount })));
                     });


            var inputData = new List<FlatDTO>()
            {
                new FlatDTO(){ Supplier = "Customer1", OrderNumber = "1234", ItemNumber = "Item1", Amount = "200"},
                new FlatDTO(){ Supplier = "Customer1", OrderNumber = "1234", ItemNumber = "Item1", Amount = "500"},
                new FlatDTO(){ Supplier = "Customer1", OrderNumber = "1234", ItemNumber = "Item1", Amount = "4000"},
                new FlatDTO(){ Supplier = "Customer1", OrderNumber = "9999", ItemNumber = "Item1", Amount = "4000"},
            };
            

            var result = inputData.GroupBy(c => (c.Supplier, c.OrderNumber)).Select(f => f).AsQueryable().ProjectTo<Order>(configuration);            
        }
    }
}

Automapper 是否可以做到这一点,映射配置文件应该是什么样子来支持这种情况?

是的,这是可能的 - 但请注意:AutoMapper 也有它的局限性。 并非所有转换都适合使用 AutoMapper 处理。

请注意: List<OrderLines> OrderLines { get; set; } List<OrderLines> OrderLines { get; set; } List<OrderLines> OrderLines { get; set; }必须是public

我没有所有的细节是的,但基本上你可以创建一个从IEnumerable<FlatDTO>Order的地图。 我会想出一个例子。

例子

CreateMap<IEnumerable<FlatDTO>, Order>()
   .ForMember(d => d.AccountName, o => o.MapFrom(s=> s.Select(c => c.Supplier).FirstOrDefault()))
   .ForMember(d => d.OrderLines, o => o.MapFrom(s=> s.Select(c => new OrderLines()
       {
           Amount = c.Amount,
           Item = c.ItemNumber,
       })));

如果第 2 行的值为“客户 2”,Automapper 将如何处理? 覆盖第一个值,即胜利中的最后一个?

根据您的映射逻辑,这取决于。 您甚至可以使用AfterMapBeforeMap方法对这些双打进行检查 - 但不会使其更快。

理想情况下,您的初始集合可以映射到单个订单,因此包含单个客户。 - 否则,您将需要从IEnumerable<FlatDTO>IEnumerable<Order>的映射 - 这确实是在IEnumerable<FlatDTO>极限。


测试员

static void Main(string[] args)
{
    var dtos = new[]
    {
       new FlatDTO() {Supplier = "you", Amount = "10", ItemNumber = "1", OrderNumber = "123"},
       new FlatDTO() {Supplier = "you", Amount = "12", ItemNumber = "2", OrderNumber = "234"}
    };

    var config = new MapperConfiguration(cfg => cfg.AddProfile<MyAutomapperProfile>());
    var mapper = config.CreateMapper();

    var order = mapper.Map<IEnumerable<FlatDTO>, Order>(dtos);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM