C# 将子查询限制在第一行的Lambda语法是什么?

C# 将子查询限制在第一行的Lambda语法是什么?,c#,sql,linq,C#,Sql,Linq,我有一个数据库,里面有商品表、税表、税表和商品价格表。除了ItemPrice表之外,这些关系非常简单。在ItemPrice表中,给定ItemId可以有多行,因为位置可以覆盖在区域级别指定的价格。每个记录必须包含RegionId或LocationId,但不能同时包含两者,并且两者都不能为null 项目价格 身份证件 项目ID LocationId可为空 价格 RegionId可为空 项目 身份证件 名字 税 身份证件 名称 类型 价值观 塔克斯泰姆 项目ID 滑行 我使用的ABP框架利用了存储库模

我有一个数据库,里面有商品表、税表、税表和商品价格表。除了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
               };