【问题标题】:Order by must be called before calling a skip在调用跳过之前必须调用 Order by
【发布时间】:2015-01-20 16:53:14
【问题描述】:

尝试执行跳过方法时出现错误。仅 LINQ to Entities 中的排序输入支持“跳过”方法。必须在方法“Skip”之前调用方法“OrderBy”。

我很清楚 orderby 必须在调用 skip 之前调用,并且我在直接调用之前的另一个函数中在 skip 之前调用它。

AddOrderBy(AdvTitleResults, ColumnNumber, OrderByDesc);

var SearchTitles = AdvTitleResults.Skip(PageNum * NumberOfResults)
                                  .Take(NumberOfResults).ToList();

order by 函数看起来像这样默认确保它总是被分配:

private void AddOrderBy(IQueryable<Title> Results, int ColumnNumber, bool OrderByDesc)
{
    switch (ColumnNumber)
    {
        case 1:
            if (OrderByDesc)
                Results = Results.OrderByDescending(t => t.FK_ContentType);
           else
                Results = Results.OrderBy(t => t.FK_ContentType);
            break;
        case 2:
            if (OrderByDesc)
                Results = Results.OrderByDescending(t => t.TitleFullName);
            else
                Results = Results.OrderBy(t => t.TitleFullName);
            break;
        default:
            if (OrderByDesc)
                Results = Results.OrderByDescending(t => t.ID);
            else
                Results = Results.OrderBy(t => t.ID);
            break;
    }
}

谁能解释为什么这不起作用?

【问题讨论】:

    标签: c# linq skip


    【解决方案1】:

    因为您实际上并没有更改AdvTitleResults,所以您正在更改参数的值。您需要使用ref 关键字才能使其工作:

    AddOrderBy(ref AvTitleResults, ColumnNumber, OrderByDesc);
    
    private void AddOrderBy(ref IQueryable<Title> Results, 
                            int ColumnNumber, 
                            bool OrderByDesc)
    

    或者您可以使用 LINQ 样式并将其作为扩展方法,然后返回查询:

    private IOrderedQueryable<Title> AddOrderBy(this IQueryable<Title> Results, int ColumnNumber, bool OrderByDesc)
    {
        switch (ColumnNumber)
        {
            case 1:
                if (OrderByDesc)
                    return Results.OrderByDescending(t => t.FK_ContentType);
               else
                    return Results.OrderBy(t => t.FK_ContentType);
                break;
            case 2:
                if (OrderByDesc)
                    return Results.OrderByDescending(t => t.TitleFullName);
                else
                    return Results.OrderBy(t => t.TitleFullName);
                break;
            default:
                if (OrderByDesc)
                    return Results.OrderByDescending(t => t.ID);
                else
                    return Results.OrderBy(t => t.ID);
                break;
        }
    }
    

    这样您就可以像调用任何其他 LINQ 方法一样调用它:

    var SearchTitles = AdvTitleResults
          .AddOrderBy(ColumnNumber, OrderByDesc)
          .Skip(PageNum * NumberOfResults)
          .Take(NumberOfResults)
          .ToList();
    

    编辑:

    IQueryable 不是一个类,默认情况下不应该通过 ref 传递吗?

    IQueryable&lt;Title&gt; 不是一个类,但它是一个引用类型。但是引用类型实际上并不是通过引用传递的。当你传递一个引用类型时,你的变量所持有的引用值会复制到一个新的变量中。是这样的:

    string foo = "Foo";
    string bar = foo; // copy foo's reference into bar
    

    现在,如果您为 bar 分配新引用,它不会更改 foo

    bar = "bar";
    

    因为它们是保存对同一地址的引用的不同变量。但是当您使用ref 关键字时,引用值不会被复制。相反,您可以认为变量本身已被传递。这是理解这一点的最简单方法。我不知道如何在 C# 语法中重现这种行为。

    【讨论】:

    • 他真的应该返回新的查询,而不是使用ref
    • isn't IQueryable 一个类不应该默认通过 ref 传递吗?
    • @Space 确实如此。这不会改变您通过值而不是通过引用传递对列表的引用这一事实。
    • @Space 是的,它会的,因为传入的值是对列表的引用,而不是对变量的引用(它包含对列表的引用)。您可以修改列表,但不能修改指向该列表的变量(除非您使用ref)。
    • @Space 使用类型成员和分配新引用是不同的事情。我添加了关于 ref 行为的解释,希望对您有所帮助
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 1970-01-01
    相关资源
    最近更新 更多