【发布时间】:2020-02-16 03:11:49
【问题描述】:
我有以下课程
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 表达式 'Where(source: DbSet, predicate: (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)
有没有办法使用我的第一种查询方式?我做错了什么,我的类没有明确定义吗?
【问题讨论】:
-
隐藏在属性中的公式通常无法转换为 LINQ。这在技术上是不可能的。只能翻译 where-select 子句中的公式。试着用不同的方式表达。从外部查看您的所有数据。在那里您可以进行连接、求和、分组等操作。您的构造仅适用于 LINQ to 对象,因为不需要将其转换为 SQL。
-
@Holger ,你的意思是我必须在我的 SQL 数据库中创建视图吗?
-
不,您必须在一个地方、一行中形成一个查询。不是
.Where(order => !order.PaidCompletely),而是.Where(order => OrderItems.Sum(x => x.TotalPrice))-Payments.Sum(x => x.Amount)>0)这只是演示方法,它不是最终解决方案。这样一来,LINQ 就有机会,至少可以得到公式。 LINQ 在运行时完成,没有可用的源,只有编译的机器代码。 LINQ 无法将机器代码转换为 SQL。在 Lambda 中,代码不是直接的机器代码,而是 Expession>,这是一种存储的源代码。 -
No, you have to form a Query in One Place, in one line好吧,严格来说这不是真的。它可以跨越多行代码。但我同意@Holger 的其余评论。 -
@Holger 这仍然是一个相当神秘的答案:-/。我是否应该在模型中定义一个 IQueryable 方法,以便在需要时调用它?
标签: c# sql-server entity-framework-core