Как сгруппировать данные из базы данных в DTO?

Как сгруппировать данные из базы данных в dto?

Например, я хочу, чтобы мой вывод был таким:

{
    id: "random-id-tst",
    years: [
        {
            year: 1,
            productIds: ['guid-id-1', 'guid-id-2'],
        },
        {
            year: 2,
            productIds: ['guid-id-3'],
        }
    ]
}

Но я борюсь и пробовал много вещей и дошел до этого момента:

{
    id: "random-id-tst",
    years: [
        {
            year: 1,
            productIds: ['guid-id-1'],
        },
        {
            year: 1,
            productIds: ['guid-id-2'],
        },
        {
            year: 2,
            productIds: ['guid-id-3'],
        },
    ]
}
public class Order
{
    public Guid ID{ get; set; }

    public ICollection<OrderLine> OrderLines { get; set; }
}
public class OrderLine
{ 
    public Guid OrderID { get; set; }
    public Order Order { get; set; }
    public Guid ProductID { get; set; }
    public Product Product { get; set; }
    public int Year { get; set }
}
public class Product
{
    public Guid ID { get; set; }        
    public ICollection<OrderLine> OrderLines { get; set; }
}
 public class OrderDto
    {
        public Guid ID { get; set; }
        public IEnumerable<YearsDto> Years { get; set; }
    }
public class YearDto
{
    public int Year { get; set; }
    public ICollection<Guid> ProductIds { get; set; }
}

Я пробовал много вещей, но каждый раз получаю разные ошибки.

Вот что я сделал:

var orderLines = (await _context.OrderLine
    .Where(s => s.orderID == orderId)
    .ToListAsync()).GroupBy(ol => ol.Year);


var order = (await _context.Order
    .Where(order => order.ID == orderId)
    .Select(x =>
        new OrderDto()
        {
            ID = order.ID,
            Years = orderLines.Select(ss => new YearsDto()
            { 
                Year = 1,
            }),
        }
    ).FirstAsync());


return order;

Как вы можете видеть, я жестко закодировал Year и не включил productIds, потому что по какой-то причине я не могу ссылаться на ss.Year или ss.Product, а также когда я запускаю это, это дает мне ошибку: InvalidOperationException: variable '__Select_1' of type 'System.Collections.Generic.IEnumerable`1[YearsDto]' referenced from scope '', but it is not defined

Может ли кто-нибудь указать мне в правильном направлении, как решить мою проблему?


person nnnn    schedule 16.05.2020    source источник


Ответы (3)


Этот код должен дать вам нужный результат:

            var order = _context.OrderLine
                .Include(o => o.OrderLines)
                .Where(s => s.Id == orderId)
                .First();

            var orderDto = new OrderDto()
            {
                ID = order.Id,
                Years = order.OrderLines.ToLookup(ol => ol.Year).Select(g => new YearDto() {Year = g.Key, ProductIds = g.ToList().Select(x => x.ProductID).ToList()})
            };

person Jakub Kozera    schedule 16.05.2020
comment
Пришлось внести некоторые изменения, но теперь он работает! Большое спасибо! - person nnnn; 16.05.2020

В вашей первой группе вы, вероятно, хотите что-то вроде

var orderLines = (await _context.OrderLine
    .Where(s => s.orderID == orderId)
    .ToListAsync()).GroupBy(ol => ol.Year, (key, group) => new { Year = key, Items = group.ToList()});

Таким образом, ваш конечный объект будет перечисляемым анонимным элементом, содержащим свойства Year и свойства Items, принадлежащие этому году.

Таким образом, остальная часть вашего запроса (только для того, чтобы он скомпилировал и извлек нужные вам данные) может быть преобразована в:

var order = (await _context.Order
    .Where(order => order.ID == orderId)
    .Select(x =>
        new OrderDto()
        {
            ID = order.ID,
            Years = orderLines.Select(ss => new YearsDto()
            { 
                Year = ss.Year,
                ProductsIds = ss.Items.Select(i => i.ProductID)
            }),
        }
    ).FirstAsync());


return order;
person Sotiris Koukios-Panopoulos    schedule 16.05.2020
comment
Все еще есть InvalidOperationException. Получил работу с ответом кебека. Спасибо за ваше время! - person nnnn; 16.05.2020

Поскольку вам не нужны никакие дополнительные данные в вашем OrderDto, кроме его идентификатора (который у вас уже есть), вы можете сделать это следующим образом:

var years  = ( await _context.OrderLine
    .Where(s => s.orderID == orderId)
    .Select( ol => new {ol.Year, ol.ProductID})
    .ToListAsync())
    .GroupBy(ol => ol.Year)
    .Select(g =>  new YearDto 
    { 
         Year = g.Key, 
         ProductIds = g.Select(i => i.ProductID).ToList() }
    )
    .ToList();
var orderDto = new OrderDto {ID = orderId; Years = years };

Хотя вы потеряете проверку того, что заказ существует в БД, но вы можете запросить его отдельно.

person Guru Stron    schedule 16.05.2020