C# 将子查询限制在第一行的Lambda语法是什么?
我有一个数据库,里面有商品表、税表、税表和商品价格表。除了ItemPrice表之外,这些关系非常简单。在ItemPrice表中,给定ItemId可以有多行,因为位置可以覆盖在区域级别指定的价格。每个记录必须包含RegionId或LocationId,但不能同时包含两者,并且两者都不能为null 项目价格 身份证件 项目ID LocationId可为空 价格 RegionId可为空 项目 身份证件 名字 税 身份证件 名称 类型 价值观 塔克斯泰姆 项目ID 滑行 我使用的ABP框架利用了存储库模式。我目前拥有的代码如下:C# 将子查询限制在第一行的Lambda语法是什么?,c#,sql,linq,C#,Sql,Linq,我有一个数据库,里面有商品表、税表、税表和商品价格表。除了ItemPrice表之外,这些关系非常简单。在ItemPrice表中,给定ItemId可以有多行,因为位置可以覆盖在区域级别指定的价格。每个记录必须包含RegionId或LocationId,但不能同时包含两者,并且两者都不能为null 项目价格 身份证件 项目ID LocationId可为空 价格 RegionId可为空 项目 身份证件 名字 税 身份证件 名称 类型 价值观 塔克斯泰姆 项目ID 滑行 我使用的ABP框架利用了存储库模
var taxItems = _TaxItemRepository
.GetAllIncluding(ti => ti.Item, ti => ti.Tax, ti => ti.Item.ItemPrice)
.Where(ti =>
(ti.ItemId == ItemId)
&&
(
(ti.Item.ItemPrice.LocationId.HasValue && ti.Item.ItemPrice.LocationId == LocationId)
||
(!ti.Item.ItemPrice.LocationId.HasValue && ti.Item.ItemPrice.RegionId == locationCacheItem.RegionId)
)
);
不幸的是,它并不等同于提供正确结果的以下SQL:
declare @ItemId bigint, @LocationId bigint, @RegionId bigint
set @ItemId = 1
set @LocationId = 1
set @RegionId = 1
select ti.TaxId as TaxId, ti.ApplyTax as ApplyTax, ip.Price, tx.Value as TaxValue, tx.SpecifyItems, tx.TaxType, tx.UseNetPrice
from TaxItem ti
inner join Tax tx on tx.id = ti.TaxId
inner join Item on ti.ItemId = Item.Id
inner join
(
select top 1 locationId, regionId, ItemId, Price
from ItemPrice
where ItemId = @ItemId and
(
(LocationId is not null and LocationId = @locationId) OR
(LocationId is null and RegionId = @RegionId)
)
) ip on ip.ItemId = Item.Id
ItemID 1的ItemPrice表中有两条记录:
LocationId Price RegionId
1 1.25 NULL
NULL 1.50 1
如何获取Lambda表达式以将子查询限制在第一行?您不需要使用GetAllIncluding方法,因为它似乎包含整个集合…我认为Abion47的评论是关于钱的,但是我通过升级到EF Core 2.1.1并使用Query.FromSQL方法执行SQL解决了这个问题。我认为这是使用Lambda表示法很难表达查询的情况之一,而使用SQL执行查询效率更高
我不知道ABP框架,这是简单的Linq:
var taxItems = from ti in context.TaxItem
let ip = ti.Item.ItemPrice
.FirstOrDefault(x => x.LocationId == LocationId ||
x.RegionId == locationCacheItem.RegionId)
select new {
TaxId = ti.TaxId,
ApplyTax = ti.ApplyTax,
Price = ip.Price,
TaxValue = ti.Tax.Value,
SpecifyItems = ti.Tax.SpecifyItems,
TaxType = ti.Tax.TaxType,
UseNetPrice = ti.Tax.UseNetPrice
};
你试过使用吗。首先?是的。它将主结果集限制在第一行,而不是子查询SQL版本的子查询中有一个select Top 1最明智的方法可能是将C版本分为两个查询-首先执行子查询,然后将结果存储在临时变量中,然后在主查询中检查它。只是一个小问题:如果没有排序顺序,第一行的概念是危险的。在某些情况下,对于人类来说,创建日期、id等可能是显而易见的。但是,您不应该依赖默认的返回订单,因为它不能保证是确定性的。那么ti.Item.ItemPrice的类型是什么呢?SQL查询表明Item具有多个ItemPrices,因此它应该是一个集合。我想知道ti.Item.ItemPrice.LocationId是否可以编译。此外,您可能毕竟可以使用LINQ,但使用不同的语句。
var taxItems = from ti in context.TaxItem
let ip = ti.Item.ItemPrice
.FirstOrDefault(x => x.LocationId == LocationId ||
x.RegionId == locationCacheItem.RegionId)
select new {
TaxId = ti.TaxId,
ApplyTax = ti.ApplyTax,
Price = ip.Price,
TaxValue = ti.Tax.Value,
SpecifyItems = ti.Tax.SpecifyItems,
TaxType = ti.Tax.TaxType,
UseNetPrice = ti.Tax.UseNetPrice
};