Выберите строки с минимальной датой в запросе на соединение - PullRequest
0 голосов
/ 23 марта 2020

Я использую Entity Framework и LINQ two, выполняю соединение между этими двумя таблицами:

var query =
        orders.Join(
        orderdetails,
        order => order.Code,
        orderdt => orderdt.Order.Code,            
        (order, orderdt)            
        => new
        {
            Code = order.Code,
            WarehouseDivision = orderdt.WarehouseDivision,
            Type = order.Type,
            SupplierCode = order.SupplierCode,
            SupplierDescription = order.SupplierDescription,
            ExpectedDeliveryDate = orderdt.ExpectedDeliveryDate
        });

соединение работает нормально. Теперь для каждой строки соединения мне нужно выбрать строку с минимальной датой ожидаемой доставки. Любой намек на то, как этого добиться?

1 Ответ

0 голосов
/ 23 марта 2020

Я вижу что-то странное в вашем Присоединении.

Каждый ордер имеет код. Каждый OrderDetail имеет Order, который также имеет код.

Если существует отношение один-ко-многим между Orders и OrderDetails, то каждый Order имеет ноль или более OrderDetails. Каждый OrderDetail принадлежит ровно одному Order, а именно Order, на который указывает внешний ключ. Это тот же Order, что и OrderDetail.Order?

В этом случае Order.Code равен OrderDetail.Order.Code для каждого OrderDetail этого кода. Не очень полезно выполнять объединение этих значений.

Я думаю, что вы имеете в виду объединение по первичному ключу и внешнему ключу.

В любом случае, независимо от того, присоединяетесь ли вы к ключам или коду свойства, решение вашей проблемы - выполнить GroupJoin вместо Join.

Если вы следовали первым соглашениям кода структуры сущностей *1014*, у вас будет что-то похожее на это:

class Order
{
    public int Id {get; set;}    // Primary key
    ...                          // other Order properties

    // every Order has zero or more OrderDetails (one-to-many)
    public virtual ICollection<OrderDetail> OrderDetails {get; set;}
}

class OrderDetail
{
    public int Id {get; set;}
    public DateTime ExpectedDeliveryDate {get; set;}
    ...                          // other OrderDetail properties

    // every OrderDetail belongs to exactly one Order, using foreign key
    public int OrderId {get; set;}
    public virtual Order Order {get; set;}
}

Возможно, вы использовали разные идентификаторы для своих свойств, но главное - это виртуальные свойства.

В структуре сущностей не виртуальные свойства представляют столбцы в В таблице виртуальные свойства представляют отношения между таблицами (один ко многим, многие ко многим).

Требование

От каждого заказа, дайте мне некоторые свойства, вместе с некоторыми свойствами OrderDetail с минимальной ExpectedDeliveryDate.

Решение с GroupJoin

GroupJoin для первичного / внешнего ключа:

var OrdersWithOldestOrderDetail = dbContext.Orders  // GroupJoin Orders 
    .GroupJoin(dbContext.OrderDetails,              // with OrderDetails
    order => order.Id,                              // from every Order take the Id
    orderDetail => orderDetail.OrderId,             // from every OrderDetail take the OrderId
    (order, orderDetailsOfThisOrder) => new         // take the Order with all its matchin OrderDetails
    {                                               // to make one new
        // Select the Order properties that you plan to use:
        ...

        // Select the OrderDetail with the minimum ExpectedDeliveryDate
        // To do this, order by ascending deliveryDate
        // then Select the properties you want to used
        // and take the FirstOrDefault
        EarliestDeliveredOrderDetail = orderDetailsOfThisOrder
           .OrderBy(orderDetail => orderDetail.ExpectedDeliveryDate)
           .Select(orderDetail => new
           {
               ...
           })
           .ToList(),
    });

Если вы действительно хотите присоединиться к свойствам, которые вы сказали:

var result = dbContext.Orders                  // GroupJoin Orders 
    .GroupJoin(dbContext.OrderDetails,         // with OrderDetails
    order => order.Code,                       // from every Order take the Code
    orderDetail => orderDetail.Order.Code,     // from every OrderDetail take Order.Code
    (order, orderDetailsWithThisCode) => new   // take the Order with all its matchin OrderDetails
    {   
        ... etc, same as above

Более простое решение с использованием ICollection

Если вы используете платформу сущностей и вам нужно выберите «Все заказы с его OrderDetails», «Все школы с его учащимися», «Все продукты с его компонентами», фактически: все элементы вместе со всеми связанными подпунктами, как правило, проще использовать ICollections вместо выполнения a само присоединение:

var OrdersWithOrderDetails = dbContext.Orders.Select(order => new
{
    // Select the Order properties that you plan to use:
    ...

    EarliestDeliveredOrderDetail = order.OrderDetails
        .OrderBy(orderDetail => orderDetail.ExpectedDeliveryDate)
        .Select(orderDetail => new
        {
            // Select the OrderDetail properties that you plan to use:
            ...
        })
        .FirstOrDefault(),
   })

Посмотрите, как естественно будет, если вы используете ICollections вместо (Group-) соединения? Entity Framework знает ваши отношения и выполняет правильное соединение для вас с правильными (внешними) ключами.

На самом деле, я редко создаю само себя. Большую часть времени я использую виртуальные свойства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...