【问题标题】:LINQ .OrderBy creates nested casingLINQ .OrderBy 创建嵌套套管
【发布时间】:2019-09-02 11:51:28
【问题描述】:

我正在尝试查询表并根据状态列以指定的自定义顺序返回行。

这是一个非常直接的SQL 查询:

SELECT  * From Table1
WHERE Id = 1
ORDER by CASE 
      WHEN [Status] = 'Status1' THEN 1
      WHEN [Status] = 'Status2' THEN 2
      WHEN [Status] = 'Status3' THEN 3
      WHEN [Status] = 'Status4' THEN 4
      WHEN [Status] = 'Status5' THEN 5
      WHEN [Status] = 'Status6' THEN 6
      WHEN [Status] = 'Status7' THEN 7
      WHEN [Status] = 'Status8' THEN 8
      WHEN [Status] = 'Status9' THEN 9
      WHEN [Status] = 'Satus10' THEN 10
      WHEN [Status] = 'Status11' THEN 11
      ELSE [Status] END ASC

我正在尝试使用 LINQ 完成相同的查询。

var data = _myContext.Table1.Where(l => l.Id == 1).Select(lp =>
            new DataModel
            {
                Id = lp.Id,
                Status = lp.Status,
                ...
            })
            .OrderBy(l => 
                       l.Status == StatusEnum.Status1.ToString() ? 1 : 
                       l.Status == StatusEnum.Status2.ToString() ? 2 : 
                       l.Status == StatusEnum.Status3.ToString() ? 3 : 
                       l.Status == StatusEnum.Status4.ToString() ? 4 : 
                       l.Status == StatusEnum.Status5.ToString() ? 5 : 
                       l.Status == StatusEnum.Status6.ToString() ? 6 : 
                       l.Status == StatusEnum.Status7.ToString() ? 7 : 
                       l.Status == StatusEnum.Status8.ToString() ? 8 : 
                       l.Status == StatusEnum.Status9.ToString() ? 9 : 
                       l.Status == StatusEnum.Status10.ToString() ? 10 : 
                       l.Status == StatusEnum.Sattus11.ToString() ? 11 : 0
            );

但是这个查询失败了:

案例表达式只能嵌套到第 10 级。

查看分析器,我看到 EF 创建了以下查询,但由于我指定了超过 10 个值,因此返回失败:

exec sp_executesql N'SELECT [l].[Id],[l].[Status], ...
FROM [Table1] AS [l]
WHERE [l].[Id] = @__id_0
ORDER BY CASE
    WHEN [l].[Status] = @__ToString_1
    THEN 1 ELSE CASE
        WHEN [l].[Status] = @__ToString_2
        THEN 2 ELSE CASE
            WHEN [l].[Status] = @__ToString_3
            THEN 3 ELSE CASE
                WHEN [l].[Status] = @__ToString_4
                THEN 4 ELSE CASE
                    WHEN [l].[Status] = @__ToString_5
                    THEN 5 ELSE CASE
                        WHEN [l].[Status] = @__ToString_6
                        THEN 6 ELSE CASE
                            WHEN [l].[Status] = @__ToString_7
                            THEN 7 ELSE CASE
                                WHEN [l].[Status] = @__ToString_8
                                THEN 8 ELSE CASE
                                    WHEN [l].[Status] = @__ToString_9
                                    THEN 9 ELSE CASE
                                        WHEN [l].[Status] = @__ToString_10
                                        THEN 10 ELSE CASE
                                            WHEN [l].[Status] = @__ToString_11
                                            THEN 11 ELSE 0
                                        END
                                    END
                                END
                            END
                        END
                    END
                END
            END
        END
    END
END',N'@__id_0 int,@__ToString_1 nvarchar(4000),@__ToString_2 nvarchar(4000),@__ToString_3 nvarchar(4000),@__ToString_4 nvarchar(4000),@__ToString_5 nvarchar(4000),@__ToString_6 nvarchar(4000),@__ToString_7 nvarchar(4000),@__ToString_8 nvarchar(4000),@__ToString_9 nvarchar(4000),@__ToString_10 nvarchar(4000),@__ToString_11 nvarchar(4000)',@__id_0=1,@__ToString_1=N'Status1',@__ToString_2=N'Status2',@__ToString_3=N'Status3',@__ToString_4=N'Status4',@__ToString_5=N'Status5',@__ToString_6=N'Status6',@__ToString_7=N'Status7',@__ToString_8=N'Status8',@__ToString_9=N'Status9',@__ToString_10=N'Status10',@__ToString_11=N'Status11'

有没有办法写这个查询,所以它不使用ELSE CASE,只匹配上面的SQL查询?

我确实没有几个选项可以绕过这个。编写一个存储过程并获取我需要的输出或将查询存储在没有OrderBy 的列表中并订购列表。但我很好奇是否有办法在该查询中执行此操作。

【问题讨论】:

  • SQL 查询工作正常。是需要修改 LINQ 查询。

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


【解决方案1】:

这是一个已知的当前 EF Core 限制,由 #12729 Flatten CASE expressions to avoid error "Case expressions may only be nested to level 10" 跟踪。

很遗憾,根本没有计划解决,也没有提供解决方法。使用值转换器也不起作用。

您能做的最好的可能就是创建、映射和使用database scalar function

【讨论】:

  • 这很不幸。感谢您提供该问题的链接。
  • 我最终使用了您建议的链接中的context.Set<Customer>().FromSql($@"...")。谢谢!
  • 看来他们终于解决了这个问题。在 3.1.4 中,它将被修复。耶!! github.com/dotnet/efcore/issues/12729
【解决方案2】:

升级到 3.1.4 版(尚不可用,但很快就会推出)。本期has been fixed there.

【讨论】:

    【解决方案3】:

    这个答案不是 LINQ,但如果您创建一个与您的 CASE 对应的计算列,您可以按此列排序。您可以在计算列中使用函数,如果该函数很简单,则可以存储该列并为其编制索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多