c# - 根据子集合总和的比较执行单个查询

标签 c# sql-server entity-framework-core

我有以下类(class)

    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();

报错

The LINQ expression 'Where(source: DbSet, predicate: (o) => !(o.PaidCompletely))' could not be translated...

以下工作正常,但我必须在查询中再次重写所有逻辑,同时我还在类中定义了逻辑:

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)

没有办法用我第一种查询方式吗?我做错了什么,我的类(class)没有明确定义吗?

最佳答案

我已经试过了:

    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 表达式的唯一原因是性能。 您无法针对可读性或美观进行优化。

关于c# - 根据子集合总和的比较执行单个查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58462412/

相关文章:

sql - 如何在 sql server 2008 的存储过程中使用 if 比较两个字符串?

sql-server - 在 TSQL 上尝试并捕捉 - 捕捉未捕捉

stored-procedures - 如何使用 blazor 执行存储过程

c# - 可序列化字典,如何设置键名?

c# - 编程/设计决策如何影响引擎盖下的性能?

javascript - 在 d3.js 图表中回显 JSON

entity-framework - 使用 EF Core 3.1 将 SQL 查询挂载到 EXTRACT postgresql 函数

c# - 如何使用 Entity Framework Core 功能来更改我的数据库?

c# - 如何在 HTTPPOST 中读取 HTML.RadioButtonFor 的选定值?

c# - 如何使用 ActionResult<T> 进行单元测试?