Automapper Unflatten to List
Tôi có dữ liệu dạng bảng phẳng mà tôi cần chuyển thành dữ liệu phân cấp và tôi đang cố gắng thực hiện việc này với AutoMapper. Đây là bản phác thảo của nguồn DTO dạng bảng và các lớp đích chính / chi tiết.
public class FlatDTO
{
public string Supplier { get; set; }
public string OrderNumber { get; set; }
public string ItemNumber { get; set; }
public string Amount { get; set; }
}
và các đối tượng đích trông như thế này:
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; }
}
Hồ sơ Automapper của tôi trông giống như sau:
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();
}
}
Hàm thực hiện Transform:
public Order Transform (List<FlatDto> data)
{
var output = injectedFromCtorIMapper.Map<Order>(data);
//throws AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping
}
Dữ liệu nguồn mẫu:
Customer1 1234 Item1 200
Customer1 1234 Item2 500
Customer1 1234 Item3 4000
Mục tiêu sẽ trông giống như (không thực sự là Json nhưng trông đẹp hơn):
Order
{
AccountName = "Customer 1",
OrderNumber = "1234",
OrderLines [
OrderLine
{
Item: "Item1",
Amount: 200
},
OrderLine
{
Item: "Item2",
Amount: 500
}
OrderLine,
{
Item: "Item3",
Amount: 4000
}
]
}
Một số câu hỏi:
Điều này có khả thi với Automapper không và hồ sơ ánh xạ sẽ như thế nào để hỗ trợ tình huống này?
Automapper sẽ xử lý như thế nào nếu hàng 2 có giá trị là 'Khách hàng 2'? Ghi đè giá trị đầu tiên tức là giá trị cuối cùng trong các trận thắng?
Trả lời
Điều này có khả thi với Automapper không và hồ sơ ánh xạ sẽ như thế nào để hỗ trợ tình huống này?
Có, điều này là có thể - nhưng hãy lưu ý: AutoMapper cũng có những hạn chế của nó. Không phải tất cả các phép biến đổi đều phù hợp để xử lý với AutoMapper.
Lưu ý: List<OrderLines> OrderLines { get; set; }phảipublic
Tôi không có tất cả các chi tiết có, nhưng về cơ bản bạn có thể tạo một bản đồ từ IEnumerable<FlatDTO>đến Order. Tôi sẽ đưa ra một ví dụ.
Thí dụ
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,
})));
Automapper sẽ xử lý như thế nào nếu hàng 2 có giá trị là 'Khách hàng 2'? Ghi đè giá trị đầu tiên tức là giá trị cuối cùng trong các trận thắng?
Tùy thuộc vào logic ánh xạ của bạn, nó phụ thuộc. Bạn thậm chí có thể thực hiện kiểm tra các bộ đôi này bằng cách sử dụng AfterMaphoặc BeforeMapcác phương pháp - mặc dù không làm cho nó nhanh hơn.
Lý tưởng nhất là tập hợp ban đầu của bạn có thể được ánh xạ tới một đơn hàng duy nhất, do đó, chứa một khách hàng duy nhất. - Nếu không, bạn sẽ cần một ánh xạ từ IEnumerable<FlatDTO>đến IEnumerable<Order>- điều này thực sự đang đẩy các giới hạn.
Kiểm thử
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);
}
Để hoàn thành việc chỉnh sửa Stefan; đây là một ví dụ về cách bạn có thể làm điều đó nếu bạn cần có nhiều nhóm theo . Hiểu được kết quả mong đợi trong câu hỏi của bạn, bạn muốn nhóm dữ liệu chính / chi tiết trên AcccountName và OrderNumber. Điều này thực sự có thể đạt được bằng cách ánh xạ IEnumerable và bằng cách sử dụng phần mở rộng " ProjectTo " của Automapper (từ không gian tên AutoMapper.QueryableExtensions ). Trong dữ liệu mẫu của tôi, tôi đã thêm một hàng với Số thứ tự khác để minh họa điều này.
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);
}
}
}