原始查询存在问题,但EF Core把它隐藏了起来,导致所有操作都变慢。
当LINQ to SQL引入客户端评估时,它是有害的,并在Entity Framework中被删除。我想不出为什么人们认为将其添加回EF Core是个好主意,但现在它已经消失了是件好事。原始查询也无法在EF 6.2中运行。
首先,ORM负责从关系和导航属性生成连接。其次,即使在SQL中,也无法添加一个在SELECT子句中不属于GROUP BY
或聚合的字段。除非使用窗口函数,否则没有聚合函数等同于FirstOrDefault()
。
要在SQL中获取类别名称,我们必须将其包含在GROUP BY中,或者使用CTE /子查询按ID分组,然后查找类别名称,例如:
SELECT CategoryID,CategoryName,Count(*)
FROM Assets inner join AssetCategories on CategoryID=AssetCategories.ID
GROUP BY CategoryID,CategoryName
或者
SELECT CategoryID,CategoryName,Cnt
FROM (select CategoryID, Count(*) as Cnt
from Assets
group by CategoryID) a
INNER JOIN AssetCategories on CategoryID=AssetCategories.ID
在 LINQ 中与第一个查询相当的是:
var items = (from asset in Context.Assets
join assetCategory in Context.AssetCategories on asset.CategoryId equals assetCategory.Id
group asset by new {assetCategory.Id,assetCategory.CategoryName} into summary
select new AssetCategorySummary
{
CategoryId = summary.Key.Id,
CategoryName = summary.Key.Name,
TotalAsset = summary.Count()
}).ToListAsync();
如果实体被修改,例如资产具有类别属性,则查询可以减少为:
var items = (from asset in Context.Assets
group asset by new {asset.Category.Id,asset.Category.CategoryName} into summary
select new AssetCategorySummary
{
CategoryId = summary.Key.Id,
CategoryName = summary.Key.Name,
TotalAsset = summary.Count()
}).ToListAsync();
这需要一些测试来确保它创建了一个合理的查询。过去曾经有一些令人惊讶的情况,而我还没有时间检查最终 EF Core 3.0 生成的 SQL。
更新
LINQPad 6 可以使用 EF Core 3,甚至可以使用外键约束从数据库生成 DbContext。
此查询
var items = (from asset in Context.Assets
group asset by new {asset.Category.Id,asset.Category.CategoryName} into summary
select new AssetCategorySummary
{
CategoryId = summary.Key.Id,
CategoryName = summary.Key.Name,
TotalAsset = summary.Count()
}).ToListAsync();
生成一个漂亮的SQL查询:
SELECT [a0].[ID] AS [CategoryId], [a0].[CategoryName], COUNT(*) AS [TotalAsset]
FROM [Assets] AS [a]
INNER JOIN [AssetCategories] AS [a0] ON [a].[CategoryID] = [a0].[ID]
GROUP BY [a0].[ID], [a0].[CategoryName]
使用join
会生成相同的SQL查询。
FromSql
方法。更多详细信息请参见:https://entityframeworkcore.com/querying-data-raw-sql-queries - TanvirArjelselect Kategori.Id,Kategori.CategoryName,count(Varlik.Id) as [Varlık Sayısı] from Assets Varlik inner join AssetCategories Kategori on Kategori.Id = Varlik.CategoryId group by Kategori.Id,Kategori.CategoryName
- S. Aziz KazdalGroupBy(p => new { p.Id, p.CategoryName })
。 - Gert Arnold