C# IQueryable结果不同于IEnumerable
我的任务是优化一些方法,在查看代码时,我发现了这个瓶颈,如果格式不正确,我深表歉意:C# IQueryable结果不同于IEnumerable,c#,linq,linq-to-sql,linq-to-entities,C#,Linq,Linq To Sql,Linq To Entities,我的任务是优化一些方法,在查看代码时,我发现了这个瓶颈,如果格式不正确,我深表歉意: // ... IEnumerable<Card> storageCards = Db.StorageCards .Where(x => x.Active && x.DocumentType == (int)DocumentType.Import); // excludeLastDate is bool storag
// ...
IEnumerable<Card> storageCards =
Db.StorageCards
.Where(x => x.Active && x.DocumentType == (int)DocumentType.Import);
// excludeLastDate is bool
storageCards = storageCards.Where(x => (excludeLastDate && x.Date < toD)
|| (!excludeLastDate && x.Date <= toD));
return LocationPriceData(storageCards, locationId.Value);
}
private Dictionary<int, decimal> LocationPriceData(IEnumerable<Card> storageCards
, int locationId)
{
// sc.LocationId, sc.ProductId are nullable int
// sc.Price is nullable decimal
// sc.Date is datetime, not null
var result = from sc in storageCards
where sc.LocationId == locationId
group sc by sc.ProductId
into g
let price = g.OrderByDescending(t => t.Date)
.ThenByDescending(t => t.Id)
.FirstOrDefault(t => t.Price.HasValue)
where price != null
select new
{
ProductId = g.Key.Value,
Price = price.LevelInputPrice.Value
};
return result.ToDictionary(x => x.ProductId, x => x.Price);
}
以下是生成的sql:
exec sp_executesql N'SELECT
[Element1].[Id] AS [Id],
[Project2].[ProductId] AS [ProductId],
[Element1].[LevelInputPrice] AS [LevelInputPrice]
FROM (SELECT
[Distinct1].[ProductId] AS [ProductId]
FROM ( SELECT DISTINCT
[Extent1].[ProductId] AS [ProductId]
FROM [dbo].[StorageCard] AS [Extent1]
WHERE ((([Extent1].[Active] = 1) AND (10 = [Extent1].[DocumentType])) OR (40 = [Extent1].[DocumentType]) OR ((70 = [Extent1].[DocumentType]) AND ([Extent1].[InputQuantity] > cast(0 as decimal(18))))) AND (((@p__linq__0 = 1) AND ([Extent1].[Date] < @p__linq__1)) OR ((@p__linq__2 <> cast(1 as bit)) AND ([Extent1].[Date] <= @p__linq__3))) AND ([Extent1].[LocationId] = @p__linq__4)
) AS [Distinct1] ) AS [Project2]
CROSS APPLY (SELECT TOP (1)
[Extent2].[Id] AS [Id],
[Extent2].[Date] AS [Date],
[Extent2].[DocumentType] AS [DocumentType],
[Extent2].[InputQuantity] AS [InputQuantity],
[Extent2].[LevelInputPrice] AS [LevelInputPrice],
[Extent2].[Active] AS [Active],
[Extent2].[LocationId] AS [LocationId],
[Extent2].[ProductId] AS [ProductId]
FROM [dbo].[StorageCard] AS [Extent2]
WHERE ((([Extent2].[Active] = 1) AND (10 = [Extent2].[DocumentType])) OR (40 = [Extent2].[DocumentType]) OR ((70 = [Extent2].[DocumentType]) AND ([Extent2].[InputQuantity] > cast(0 as decimal(18))))) AND (((@p__linq__0 = 1) AND ([Extent2].[Date] < @p__linq__1)) OR ((@p__linq__2 <> cast(1 as bit)) AND ([Extent2].[Date] <= @p__linq__3))) AND ([Extent2].[LocationId] = @p__linq__4) AND (([Project2].[ProductId] = [Extent2].[ProductId]) OR (([Project2].[ProductId] IS NULL) AND ([Extent2].[ProductId] IS NULL))) AND ([Extent2].[LevelInputPrice] IS NOT NULL) ) AS [Element1]
WHERE [Element1].[Id] IS NOT NULL',N'@p__linq__0 bit,@p__linq__1 datetime2(7),@p__linq__2 bit,@p__linq__3 datetime2(7),@p__linq__4 int',@p__linq__0=0,@p__linq__1='2017-07-19 08:43:52.6901840',@p__linq__2=0,@p__linq__3='2017-07-19 08:43:52.6901840',@p__linq__4=11
我对LINQ中的查询语法一点也不熟悉。我有一种感觉,由于ORM的复杂性,let语句可能不受支持。但奇怪的是,它完全从SQL中省略,而不是生成错误 试着试一试:
var result = storageCards
.Where(sc => sc.LocationId == locationId)
.GroupBy(sc => sc.ProductId)
.Select(g => new {
ProductId = g.Key.Value,
Price = g.OrderByDescending(t => t.Date)
.ThenByDescending(t => t.Id)
.Where(t => t.Price.HasValue)
.Select(t => t.LevelInputPrice.Value)
.FirstOrDefault()
})
.Where(a => a.Price != null);
查看探查器,在ToDictionary行?@TadijaBagarić..哪个..接收到一个查询。。不管怎么说,这似乎就是你所说的;所以不要理会我的评论:@Rob np,谢谢你的意见。让我读了关于评估和matrialization@TadijaBagarić乍一看,似乎没有任何明显的迹象。该组应该可以很好地工作,在数据库中按null分组,在内存中的行为应该相同。我能想到的唯一解释是排序,如果有多行具有相同的日期和ID。否则,我需要查看正在操作的实际行,以及两种方法产生的结果row@SamvelPetrosov我不同意;这个bug在优化过程中出现的事实并不意味着它是一个适合于代码审查的问题。即使它是合适的,也不意味着它应该迁移;我尝试了一个类似的let语句,Linq2Sql很好地处理了它。Tnx,不是我需要的答案,但它让我找到了答案。
var result = storageCards
.Where(sc => sc.LocationId == locationId)
.GroupBy(sc => sc.ProductId)
.Select(g => new {
ProductId = g.Key.Value,
Price = g.OrderByDescending(t => t.Date)
.ThenByDescending(t => t.Id)
.Where(t => t.Price.HasValue)
.Select(t => t.LevelInputPrice.Value)
.FirstOrDefault()
})
.Where(a => a.Price != null);