【问题标题】:Linq query in EF Core 2 when using joins and pagination order by column alias doesn't workEF Core 2 中的 Linq 查询在按列别名使用联接和分页顺序时不起作用
【发布时间】:2018-02-01 10:32:44
【问题描述】:

我们目前正在尝试使用LinqEF Core 2 将排序写入我们的服务器端分页。我们遇到了Linq 生成的列别名在使用分页时不起作用的问题。但是,如果我们不分页,它会按预期工作。

输出查询中的所有列都是别名,因为我们在模型中具有不同的属性名称,并且数据库列名称不同,但这不应该对我们的知识产生影响。

这是没有分页的Linq 查询:

var source = from p in _ppmRepository.GetAll()
                         join jt in _jobTypeRepository.GetAll() on p.PpmFkeyInSeq equals jt.Id into jtdata
                         from jt in jtdata.DefaultIfEmpty()
                         join a in _assetRepository.GetAll() on p.PpmFkeyArSeq equals a.Id into aData
                         from a in aData.DefaultIfEmpty()
                         where p.PpmFkeyBgSeq == bldId
                         orderby p.PpmFreq
                         select new BuildingPpmListViewModel
                         {
                             PpmId = p.Id,
                             PpmFreq = p.PpmFreq,
                             PpmNextService = p.PpmNextService,
                             TotalCost = p.TotalCost,
                             PpmPeriodUnits = p.PpmPeriodUnits,
                             PpmFkeyPriDesc = p.PpmFkeyPriDesc,
                             JtTitle = jt.JtTitle,
                             AssetId = p.PpmFkeyArSeq,
                             AssetDescription = a.AssetDescription,
                             IsDeleted = p.IsDeleted

                         };
            source = source.Where(i => i.JtTitle.Contains("audit") && i.AssetDescription.Contains("df"));

这是由 ef core 产生的输出查询,有效:

SELECT [p].[PPM_SEQ] AS [PpmId], [p].[PPM_FREQ] AS [PpmFreq], [p].[PPM_NEXT_SERVICE] AS [PpmNextService], 
CAST([p].[TotalCost] AS float) AS [TotalCost], [p].[PPM_PERIOD_UNITS] AS [PpmPeriodUnits], [p].[PPM_FKEY_PRI_DESC] AS [PpmFkeyPriDesc], 
[t].[jt_title] AS [JtTitle], [p].[PPM_FKEY_AR_SEQ] AS [AssetId], [t0].[AR_DESCRIPTION] AS [AssetDescription], [p].[Deleted] AS [IsDeleted]
FROM [PPMs] AS [p]
LEFT JOIN (
    SELECT [j].*
    FROM [JobTypes] AS [j]
) AS [t] ON [p].[PPM_FKEY_IN_SEQ] = [t].[jt_seq]
LEFT JOIN (
    SELECT [a].*
    FROM [Assets] AS [a]
) AS [t0] ON [p].[PPM_FKEY_AR_SEQ] = [t0].[ar_seq]
WHERE ([p].[PPM_FKEY_BG_SEQ] = 172) AND ((CHARINDEX(N'audit', [t].[jt_title]) > 0) AND (CHARINDEX(N'df', [t0].[AR_DESCRIPTION]) > 0))
ORDER BY [PpmFreq]

这是带有分页的Linq 查询:

var source = from p in _ppmRepository.GetAll()

                         join jt in _jobTypeRepository.GetAll() on p.PpmFkeyInSeq equals jt.Id into jtdata
                         from jt in jtdata.DefaultIfEmpty()
                         join a in _assetRepository.GetAll() on p.PpmFkeyArSeq equals a.Id into aData
                         from a in aData.DefaultIfEmpty()
                         where p.PpmFkeyBgSeq == bldId
                         orderby p.PpmFreq
                         select new BuildingPpmListViewModel
                         {
                             PpmId = p.Id,
                             PpmFreq = p.PpmFreq,
                             PpmNextService = p.PpmNextService,
                             TotalCost = p.TotalCost,
                             PpmPeriodUnits = p.PpmPeriodUnits,
                             PpmFkeyPriDesc = p.PpmFkeyPriDesc,
                             JtTitle = jt.JtTitle,
                             AssetId = p.PpmFkeyArSeq,
                             AssetDescription = a.AssetDescription,
                             IsDeleted = p.IsDeleted

                         };
            source = source.Where(i => i.JtTitle.Contains("audit") && i.AssetDescription.Contains("df")).Skip(0).Take(50);

这是分页的输出,其中 PpmFreq 的 over 函数顺序是 SQL 找不到的 [p].[PPM_FREQ] 的别名:

SELECT [t1].[PpmId], [t1].[PpmFreq], [t1].[PpmNextService], [t1].[TotalCost], [t1].[PpmPeriodUnits], 
[t1].[PpmFkeyPriDesc], [t1].[JtTitle], [t1].[AssetId], [t1].[AssetDescription], [t1].[IsDeleted]
FROM (
    SELECT [p].[PPM_SEQ] AS [PpmId], [p].[PPM_FREQ] AS [PpmFreq], [p].[PPM_NEXT_SERVICE] AS [PpmNextService], 
    CAST([p].[TotalCost] AS float) AS [TotalCost], [p].[PPM_PERIOD_UNITS] AS [PpmPeriodUnits], [p].[PPM_FKEY_PRI_DESC] AS 
    [PpmFkeyPriDesc], [t].[jt_title] AS [JtTitle], [p].[PPM_FKEY_AR_SEQ] AS [AssetId], [t0].[AR_DESCRIPTION] AS [AssetDescription], 
    [p].[Deleted] AS [IsDeleted], ROW_NUMBER() OVER(ORDER BY [PpmFreq]) AS [__RowNumber__]
    FROM [PPMs] AS [p]
    LEFT JOIN (
        SELECT [j].*
        FROM [JobTypes] AS [j]
    ) AS [t] ON [p].[PPM_FKEY_IN_SEQ] = [t].[jt_seq]
    LEFT JOIN (
        SELECT [a].*
        FROM [Assets] AS [a]
    ) AS [t0] ON [p].[PPM_FKEY_AR_SEQ] = [t0].[ar_seq]
    WHERE (([p].[PPM_FKEY_BG_SEQ] = 172)) AND ((CHARINDEX(N'audit', [t].[jt_title]) > 0) 
    AND (CHARINDEX(N'df', [t0].[AR_DESCRIPTION]) > 0))
) AS [t1]
WHERE ([t1].[__RowNumber__] > 0) AND ([t1].[__RowNumber__] <= (50))

这似乎是我们的问题所在,因为我们可以稍微修改它以从数据库中获得正确的结果:

ROW_NUMBER() OVER(ORDER BY [PpmFreq]) AS [__RowNumber__]

如果我们要修改上述语句以将表别名也包含为[p].[PPM_FREQ],例如:ROW_NUMBER() OVER(ORDER BY [p].[PPM_FREQ]) AS [__RowNumber__],那么我们的问题就解决了,但对于我们当前的 linq 查询来说这似乎是不可能的。

【问题讨论】:

  • 尝试在 SQL Server Management Studio 中运行查询 )SSMS) 并查看您遇到的错误。 SSMS 中的错误消息比 c# 中的要好得多。
  • @jdweng 遗憾的是两者在错误方面相同,仍然不确定为什么生成的查询不包含对我们别名的引用。因此它总是会返回相同的错误。
  • 这是一个已知问题,已在即将发布的 2.1 版本中修复。您可以在此处查看更多详细信息和可能的解决方法github.com/aspnet/EntityFrameworkCore/issues/9535

标签: c# sql sql-server entity-framework linq


【解决方案1】:

看看下面的效果是否更好:

            var source = (from p in _ppmRepository.GetAll()
                         join jt in _jobTypeRepository.GetAll() on p.PpmFkeyInSeq equals jt.Id into jtdata
                         from jt in jtdata.DefaultIfEmpty()
                         join a in _assetRepository.GetAll() on p.PpmFkeyArSeq equals a.Id into aData
                         from a in aData.DefaultIfEmpty()
                         select new BuildingPpmListViewModel
                         {
                             PpmId = p.Id,
                             PpBgSeq = p.PpmFkeyBgSeq,
                             PpmFreq = p.PpmFreq,
                             PpmNextService = p.PpmNextService,
                             TotalCost = p.TotalCost,
                             PpmPeriodUnits = p.PpmPeriodUnits,
                             PpmFkeyPriDesc = p.PpmFkeyPriDesc,
                             JtTitle = jt.JtTitle,
                             AssetId = p.PpmFkeyArSeq,
                             AssetDescription = a.AssetDescription,
                             IsDeleted = p.IsDeleted

                         })
                         .Where(x =>  x.PpBgSeq == bldId)
                         .OrderBy(x => x.PpmFreq)
                         .ToList();

【讨论】:

  • 不幸的是,这会返回与上述查询完全相同的效果,不过感谢您的回答。
【解决方案2】:

这是我们后来直接向 ef 核心团队提交的已知问题。

这是一个已知问题,已在即将发布的 2.1 版本中修复 您可以在此处查看更多详细信息和可能的解决方法 github.com/aspnet/EntityFrameworkCore/issues/9535` 斯密特帕特尔

如果您运行夜间构建,则可以解决上述问题。

【讨论】:

    猜你喜欢
    • 2020-01-25
    • 1970-01-01
    • 2021-05-03
    • 2021-02-22
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 2019-12-17
    相关资源
    最近更新 更多