Выполнить один запрос на основе сравнения суммы дочерних коллекций - PullRequest
2 голосов
/ 19 октября 2019

У меня есть следующие классы

    public class Order
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public DateTime Date { get; set; }
        public decimal TotalPaid { get { return Payments.Sum(x => x.Amount); } }
        public decimal Total { get { return OrderItems.Sum(x => x.TotalPrice); } }
        public bool PaidCompletely { get { return Total == TotalPaid; } }
        public List<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
        public List<Payment> Payments { get; set; } = new List<Payment>();
    }

    public class OrderItem
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public decimal PricePerUnit { get; set; }
        public decimal Quantity { get; set; }
        public decimal TotalPrice { get { return PricePerUnit * Quantity; } }
    }

    public class Payment
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public decimal Amount { get; set; }
        public DateTime Date { get; set; }
    }

Я хочу получить все заказы, которые не полностью оплачены.

Следующее не работает

var OrdersNotFullyPaidShort = 
    context
    .Orders
    .Where(order => !order.PaidCompletely)
    .ToList();

предоставлениеошибка

Не удалось перевести выражение LINQ 'Где (источник: DbSet, предикат: (o) =>! (o.PaidCompletely)) "...

Следующее работает, но я должен снова переписать всю логику в запросе, в то время как у меня есть логика, также определенная в классах:

var OrdersNotFullyPaidLong =
    context
    .Orders
    .Where(order => order.OrderItems.Sum(orderItem => orderItem.PricePerUnit * orderItem.Quantity) == order.Payments.Sum(payment => payment.Amount))
    .ToList();

, и генерирует этот довольно уродливый запрос:

      SELECT [o].[Id], [o].[Date]
      FROM [Orders] AS [o]
      WHERE (((
          SELECT SUM([o0].[PricePerUnit] * [o0].[Quantity])
          FROM [OrderItems] AS [o0]
          WHERE ([o].[Id] = [o0].[OrderId]) AND [o0].[OrderId] IS NOT NULL) = (
          SELECT SUM([p].[Amount])
          FROM [Payments] AS [p]
          WHERE ([o].[Id] = [p].[OrderId]) AND [p].[OrderId] IS NOT NULL)) AND ((
          SELECT SUM([o0].[PricePerUnit] * [o0].[Quantity])
          FROM [OrderItems] AS [o0]
          WHERE ([o].[Id] = [o0].[OrderId]) AND [o0].[OrderId] IS NOT NULL) IS NOT NULL AND (
          SELECT SUM([p].[Amount])
          FROM [Payments] AS [p]
          WHERE ([o].[Id] = [p].[OrderId]) AND [p].[OrderId] IS NOT NULL) IS NOT NULL)) OR ((
          SELECT SUM([o0].[PricePerUnit] * [o0].[Quantity])
          FROM [OrderItems] AS [o0]
          WHERE ([o].[Id] = [o0].[OrderId]) AND [o0].[OrderId] IS NOT NULL) IS NULL AND (
          SELECT SUM([p].[Amount])
          FROM [Payments] AS [p]
          WHERE ([o].[Id] = [p].[OrderId]) AND [p].[OrderId] IS NOT NULL) IS NULL)

Нет ли способа использовать мой первый способ запроса? Что я делаю не так, мои классы плохо определены?

Ответы [ 2 ]

0 голосов
/ 20 октября 2019

Я думаю, что этот пост в блоге дает хорошее объяснение того, что происходит и какие возможные решения существуют:

https://daveaglick.com/posts/computed-properties-and-entity-framework

0 голосов
/ 19 октября 2019

Я пробовал это:

    var query = db.Order.Select(x => new { Id = x.Id, Date = x.Date,
                    Payments = x.Payments.Sum(y => y.Amount),
                    ToPay = x.OrderItems.Sum(y => y.PricePerUnit * y.Quantity)})
                   .Where(x => x.Payments < x.ToPay);

, и он создал

SELECT 
     [Project2].[Id] AS [Id], 
[Project2].[Date] AS [Date], 
[Project2].[C1] AS [C1], 
[Project2].[C2] AS [C2]
FROM ( SELECT 
    [Project1].[Id] AS [Id], 
    [Project1].[Date] AS [Date], 
    [Project1].[C1] AS [C1], 
    (SELECT 
        SUM([Filter2].[A1_0]) AS [A1]
        FROM ( SELECT 
            [Extent3].[PricePerUnit] * [Extent3].[Quantity] AS [A1_0]
            FROM [dbo].[OrderItems] AS [Extent3]
            WHERE [Project1].[Id] = [Extent3].[Order_Id]
        )  AS [Filter2]) AS [C2]
    FROM ( SELECT 
        [Extent1].[Id] AS [Id], 
        [Extent1].[Date] AS [Date], 
        (SELECT 
            SUM([Extent2].[Amount]) AS [A1]
            FROM [dbo].[Payments] AS [Extent2]
            WHERE [Extent1].[Id] = [Extent2].[Order_Id]) AS [C1]
        FROM [dbo].[Orders] AS [Extent1]
    )  AS [Project1]
)  AS [Project2]
WHERE ([Project2].[C1] < [Project2].[C2]) AND ([Project2].[C1] < [Project2].[C2])

Что выглядит довольно мило для меня Это может зависеть от поставщика LINQ, какой запрос создается.

Перед тем, как приступить к "уродливому" запросу, вы должны быть рады, что может быть создан правильный запрос. Единственной причиной дальнейшей оптимизации выражений LINQ является производительность. Вы не можете оптимизировать для удобочитаемости или красоты.

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