简体   繁体   English

EF Core 2.2 LINQ 查询在 EF Core 3.0 中不起作用

[英]EF Core 2.2 LINQ query not working in EF Core 3.0

Below code works fine at EF Core 2.2 bu not working on EF core 3.0下面的代码在 EF Core 2.2 上运行良好,但在 EF Core 3.0 上无法运行

 var items = (from asset in Context.Assets
              join assetCategory in Context.AssetCategories on asset.CategoryId equals assetCategory.Id
              group assetCategory by assetCategory.Id into assetCategories
              select new AssetCategorySummary
              {
                  CategoryId = assetCategories.Key,
                  CategoryName = assetCategories.Select(p => p.CategoryName).FirstOrDefault(),
                  TotalAsset = assetCategories.Count()
              }).ToListAsync();

the error I am getting:我得到的错误:

Processing of the LINQ expression 'AsQueryable(Select<AssetCategory, string>( source: NavigationTreeExpression Value: default(IGrouping<Guid, AssetCategory>) Expression: (Unhandled parameter: e), selector: (p) => p.CategoryName))' by 'NavigationExpandingExpressionVisitor' failed. LINQ 表达式的处理 'AsQueryable(Select<AssetCategory, string>( source: NavigationTreeExpression Value: default(IGrouping<Guid, AssetCategory>) Expression: (Unhandled parameter: e), selector: (p) => p.CategoryName)) '由'NavigationExpandingExpressionVisitor' 失败。 This may indicate either a bug or a limitation in EF Core.这可能表示 EF Core 中的错误或限制。 See https://go.microsoft.com/fwlink/?linkid=2101433 for more detailed information.有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101433

need help please请需要帮助

This is due to one of the breaking changes in EF Core 3.0 and that is: LINQ queries are no longer evaluated on the client这是由于EF Core 3.0中的一项重大更改,即: 不再在客户端上评估 LINQ 查询

So write the query in such way that EF Core can convert the expression into T-SQL or fetch the data into memory and then make your query.因此,以 EF Core 可以将表达式转换为 T-SQL 或将数据提取到 memory 的方式编写查询,然后进行查询。

The original query had problems but EF Core hid it under the carpet, slowing everything down.原始查询存在问题,但 EF Core 将其隐藏在地毯下,从而减慢了一切速度。

Client-side evaluation was evil when it was introduced in LINQ to SQL and removed in Entity Framework.当它在 LINQ 到 SQL 中引入并在实体框架中删除时,客户端评估是邪恶的。 I can't think why people though it would be a good idea to add it back to EF Core, but it's a good thing it's gone now.我想不出为什么人们虽然将它添加回 EF Core 是个好主意,但现在它已经消失了,这是一件好事。 The original query wouldn't run in EF 6.2 either.原始查询也不会在 EF 6.2 中运行。

The original query needs a bit of fixing, which will probably result in performance improvements.原始查询需要一些修复,这可能会提高性能。 First of all, it's the ORM's job to generate joins from relations and navigation properties.首先,从关系和导航属性生成连接是 ORM 的工作。

Second, even in SQL it's impossible to add a field in the SELECT clause that isn't part of GROUP BY or an aggregate.其次,即使在 SQL 中,也不可能在 SELECT 子句中添加不属于GROUP BY或聚合的字段。 There's no aggregate function equivalent to FirstOrDefault() unless one uses a windowing function.除非使用窗口 function,否则没有与FirstOrDefault()等效的聚合 function。

To get the category name in SQL, we'd have to either include it in GROUP BY or use a CTE/subquery to group by ID and then look up the category name, eg:要获取 SQL 中的类别名称,我们必须将其包含在 GROUP BY 中或使用 CTE/子查询按 ID 分组,然后查找类别名称,例如:

SELECT CategoryID,CategoryName,Count(*)
FROM Assets inner join AssetCategories on CategoryID=AssetCategories.ID
GROUP BY CategoryID,CategoryName

or或者

SELECT CategoryID,CategoryName,Cnt
FROM (select CategoryID, Count(*) as Cnt
      from Assets
      group by CategoryID) a 
INNER JOIN AssetCategories on CategoryID=AssetCategories.ID

The equivalent of the first query in LINQ would be: 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();

If the entities are modified so eg Asset has an Category property, the query could be reduced to:如果实体被修改,例如 Asset 具有 Category 属性,则查询可以简化为:

 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();

This need some testing though to ensure it creates a sane query.这需要一些测试以确保它创建一个健全的查询。 There have been some surprises in the past and I haven't had the time to check the generated SQL in the final EF Core 3.0过去有一些惊喜,我没有时间检查最终 EF Core 3.0 中生成的 SQL

Update更新

LINQPad 6 can use EF Core 3 and even generates a DbContext from a database using the foreign key constraints. LINQPad 6 可以使用 EF Core 3,甚至可以使用外键约束从数据库生成 DbContext。

This query这个查询

 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();

generates a nice SQL query:生成一个不错的 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]

Using join generates the same SQL query.使用join会生成相同的 SQL 查询。

you can still perform any sort of set operation on the client via client evaluation simply insert an AsEnumerable() before performing your set operation.您仍然可以通过客户端评估在客户端上执行任何类型的设置操作,只需在执行设置操作之前插入AsEnumerable()即可。 This is how all set operations were handled in pre-3.0 versions, and depending on the exact use case client evaluation may perform just as well as server evaluation.这就是在 3.0 之前的版本中处理所有集合操作的方式,并且根据确切的用例,客户端评估可能与服务器评估一样执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM