【问题标题】:Custom Sort in LINQ QueryLINQ 查询中的自定义排序
【发布时间】:2015-07-19 00:22:56
【问题描述】:

我有一个使用 LINQ 查询调用的表值函数。
正如我现在所理解的(参考here),排序需要在表值函数之外完成。这意味着,我必须在 LINQ 查询中执行此操作。

我需要一些语法方面的帮助。这是我对该函数的原始调用。

var sourceQuery = (from f in db.fGameListDataTable(competitionID, eventID,  participantType)
                   select f); 

我需要从 SQL 查询中获取此自定义排序并将其添加到 LINQ 查询中。

Order By 
    CASE 
        WHEN GameType = 'G' THEN '1'
        WHEN GroupNumber = '1' THEN '2'
        WHEN GroupNumber = '2' THEN '3'
        WHEN GroupNumber = '3' THEN '4'
        WHEN GroupNumber = '4' THEN '5'
        WHEN GameType = 'GT' THEN '6'
        WHEN GameType = 'P' THEN '7'
        WHEN GameType = 'FT' THEN '8'   
    END ASC,
    g.GameID ASC

更新

对于视觉参考,这是已排序的表格。注意顺序。

【问题讨论】:

  • 你控制SQL函数的代码吗?你不能在返回的“表”中添加一个额外的列吗?
  • 是的,这是我的职责。你能解释一下额外的列是什么意思吗?
  • 也许有什么东西在逃避我,但是你为什么不简单地从数据库函数中返回那个额外的排序列呢?然后你可以简单地根据它进行排序。
  • 实际上 - 只是尝试了你的想法。不,这不起作用,因为它不仅仅是为每一列分配一个值。例如,某些记录的 GameType 可能为“G”,并且在 GroupNumber 中为“1”。
  • 你可以在.net stackoverflow.com/questions/2013198/…使用表达式的力量

标签: c# sql linq asp-net-mvc-1


【解决方案1】:

您可以构建一个大的条件表达式。不幸的是,它将有八层嵌套(糟糕!)

var ordered = (from f in ... select ...)
    .OrderBy(f =>
        f.GameType == 'G' ? 1
    :   f.GroupNumber == '1' ? 2
    :   f.GroupNumber == '2' ? 3
    :   f.GroupNumber == '3' ? 4
    :   f.GroupNumber == '4' ? 5
    :   f.GameType == 'GT'   ? 6
    :   f.GameType == 'P'    ? 7
    :   f.GameType == 'PT'   ? 8
    :   9
    );

【讨论】:

  • 我认为这可能是解决方案。我会告诉你什么时候我可以测试出来。这会影响性能吗?
  • @madvora 我怀疑你会得到相同的生成 SQL(即使用 CASE 表达式),所以我认为性能不会有所不同。
【解决方案2】:

可以这样做:

var sourceQuery =
    (from f in db.fGameListDataTable(competitionID, eventID, participantType) select f)
    .OrderBy(f =>
    {
        int sortValue = 0;

        if (f.GameType == "G")
            sortValue = 1;
        else if (f.GroupNumber == "1")
            sortValue = 2;
        else if (f.GroupNumber == "2")
            sortValue = 3;
        else if (f.GroupNumber == "3")
            sortValue = 4;
        else if (f.GroupNumber == "4")
            sortValue = 5;
        else if (f.GameType == "GT")
            sortValue = 6;
        else if (f.GameType == "P")
            sortValue = 7;
        else if (f.GameType == "FT")
            sortValue = 8;

        return sortValue;
    }).ThenBy(f => f.GameID);

【讨论】:

    【解决方案3】:

    我仍然不明白为什么您不能使用数据库引擎根据您描述的条件生成该数字。

    您已经将其作为示例代码提供:

    Order By 
        CASE 
            WHEN GameType = 'G' THEN '1'
            WHEN GroupNumber = '1' THEN '2'
            WHEN GroupNumber = '2' THEN '3'
            WHEN GroupNumber = '3' THEN '4'
            WHEN GroupNumber = '4' THEN '5'
            WHEN GameType = 'GT' THEN '6'
            WHEN GameType = 'P' THEN '7'
            WHEN GameType = 'FT' THEN '8'   
        END ASC,
        g.GameID ASC
    

    现在,虽然我知道您可能不希望(甚至可以)在表值函数中包含此确切代码(根据您的链接,ORDER BY 需要在函数之外),但我几乎可以肯定您仍然可以使用 CASE 语句来生成附加列。

    我并不是说你应该在服务器上 ORDER BY。只需使用 CASE 语句生成附加列,您就可以将该列用作 LINQ 查询的 order by。

    在我之前的评论中,当我提到添加一个额外的列时,我的意思不仅仅是一个顺序列,我的意思是我上面写的。该额外列的值将基于您完全相同的逻辑,但将在服务器上生成,而不是尝试在 LINQ 客户端实现它。

    问候

    编辑:

    这是一个代码 sn-p,显示了它在表值函数中的样子:

    INSERT INTO @Table
      SELECT EventID, GameID, [all you other columns],
        CASE 
            WHEN GameType = 'G' THEN '1'
            WHEN GroupNumber = '1' THEN '2'
            WHEN GroupNumber = '2' THEN '3'
            WHEN GroupNumber = '3' THEN '4'
            WHEN GroupNumber = '4' THEN '5'
            WHEN GameType = 'GT' THEN '6'
            WHEN GameType = 'P' THEN '7'
            WHEN GameType = 'FT' THEN '8'   
        END
      FROM [Whatever you pull your columns from]
    

    这只是一个例子,不是实际代码。

    【讨论】:

    • 这不起作用,因为它在多个级别上进行排序。看看我的示例中的第一条记录(gameID 279)。根据这个逻辑,您首先会因为游戏类型而分配 1,然后您会用 2 覆盖它,因为它是组号 1。此外,您将有多个记录分配相同的值。这对排序有什么帮助?原始的 SQL 案例逻辑首先对一个小组进行排序,然后继续对该小组的其他级别进行排序。
    • 就像我说的,有一些东西显然在逃避我。老实说,我看不出您的示例 SQL CASE 有何不同。也许如果您发布了整个原始表格功能,那不起作用?
    【解决方案4】:

    按 ArrayList 的索引排序:

        var periods = new List<string>() 
        { "AM1", "AM2", "0", "1", "2", 
            "3", "4", "5", "5A", "5B", "6", "6X", 
            "7", "8", "9", "10", "11", "12" };
                    
        var bl2 = (from b in db.Tardies 
    as IEnumerable<Tardies> select b)
                  .ToList()
                  .OrderByDescending(b => 
    periods.IndexOf(b.period.Trim()));
    

    【讨论】:

    • 将整个表加载到内存中进行排序是一个非常昂贵且缓慢的想法。服务器拥有比任何客户端更多的 RAM 和 CPU 内核。我想说服务器也可以使用索引,这通常会导致性能提高 100-1000 倍,但是这种排序会阻止服务器使用索引
    • 谢谢!我正在使用 sql 视图,我注意到它在本地或远程查询中都很慢,但是当我加入 tabled 时,它非常快。你觉得是不是因为我的Sql tableView没有索引?
    猜你喜欢
    • 2014-09-10
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    相关资源
    最近更新 更多