Automapper Unflatten to List
Hiyerarşik verilere dönüştürmem gereken düz tablo verilerim var ve bunu yapmaya çalışıyorum AutoMapper. Burada, tablolu DTO kaynağının ve ana / ayrıntı hedef sınıflarının bir taslağı yer almaktadır.
public class FlatDTO
{
public string Supplier { get; set; }
public string OrderNumber { get; set; }
public string ItemNumber { get; set; }
public string Amount { get; set; }
}
ve hedef nesneler şuna benzer:
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 profilim şuna benziyor:
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();
}
}
Dönüşümü gerçekleştiren işlev:
public Order Transform (List<FlatDto> data)
{
var output = injectedFromCtorIMapper.Map<Order>(data);
//throws AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping
}
Örnek Kaynak Veriler:
Customer1 1234 Item1 200
Customer1 1234 Item2 500
Customer1 1234 Item3 4000
Hedef şöyle görünmeli (aslında Json değil ama daha iyi görünüyor):
Order
{
AccountName = "Customer 1",
OrderNumber = "1234",
OrderLines [
OrderLine
{
Item: "Item1",
Amount: 200
},
OrderLine
{
Item: "Item2",
Amount: 500
}
OrderLine,
{
Item: "Item3",
Amount: 4000
}
]
}
Birkaç soru:
Bu, Automapper ile mümkün müdür ve bu senaryoyu desteklemek için eşleme profili nasıl görünmelidir?
2. satırda 'Müşteri 2' değeri olsaydı Automapper nasıl davranırdı? İlk değerin, yani sonuncunun üzerine yazılsın mı?
Yanıtlar
Bu, Automapper ile mümkün müdür ve bu senaryoyu desteklemek için eşleme profili nasıl görünmelidir?
Evet, bu mümkündür - ancak şunu unutmayın: AutoMapper'ın da kendi sınırlamaları vardır. Tüm dönüşümler AutoMapper ile işlenmeye uygun değildir.
Unutmayın: List<OrderLines> OrderLines { get; set; }olmalıdırpublic
Ben tüm ayrıntıları evet yok ama temelde bir harita oluşturabilir IEnumerable<FlatDTO>için Order. Bir örnek oluşturacağım.
Misal
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. satırda 'Müşteri 2' değeri olsaydı Automapper nasıl davranırdı? İlk değerin, yani sonuncunun üzerine yazılsın mı?
Haritalama mantığınıza bağlı olarak değişir. AfterMapVeya BeforeMapyöntemlerini kullanarak bu çiftleri kontrol edebilirsiniz - yine de daha hızlı yapmaz.
İdeal olarak, ilk setiniz tek bir siparişle eşleştirilebilir, böylece tek bir müşteri içerir. - Aksi takdirde, bir haritaya ihtiyacınız IEnumerable<FlatDTO>olacak IEnumerable<Order>- bu gerçekten sınırları zorluyor.
Test cihazı
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);
}
Stefan 'ın düzenlemesini tamamlamak için; burada birden çok gruba sahip olmanız gerektiğinde bunu nasıl yapabileceğinize dair bir örnek var . Sorunuzda beklediğiniz sonucu anlamak için, HesapAdı ve Sipariş Numarası üzerindeki ana / ayrıntı verilerini gruplamak istiyorsunuz. Bu, IEnumerable'ı eşleyerek ve Automapper'in " ProjectTo " uzantısını ( AutoMapper.QueryableExtensions ad alanından ) kullanarak elde edilebilir. Örnek verilerime bunu göstermek için farklı bir OrderNumber ile bir satır ekledim.
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);
}
}
}