【问题标题】:How can I use func in a C# EF dbquery statement for sorting?如何在 C# EF dbquery 语句中使用 func 进行排序?
【发布时间】:2019-02-04 23:44:19
【问题描述】:

我必须进行多部分排序并希望动态进行。

我发现了这个问题,但不知道如何在 dbquery 语句中使用 func

No generic method 'ThenBy' on type 'System.Linq.Queryable'

如果我能让线程中的代码工作,那将是必杀技。

我看到的所有示例都在where 语句中使用then,但我需要使用该函数进行排序。

我使用 IQueryable 编写了扩展,包括用于 orderby 和 orderbydescending 的扩展。问题是thenbythenbydescending 使用iorderedqueryable

我在使用 ThenByProperty 时遇到的错误是

“System.Data.Entity.Infrastructure.DbQuery1[ORMModel.v_Brand]' cannot be converted to type 'System.Linq.IOrderedEnumerable1[ORMModel.v_Brand]”类型的对象。

当我使用类似的 OrderByProperty 扩展时,不会出现这样的错误。

真是一团糟,显然我不经常在这里发帖。无论如何,我很困惑而且一无所知,所以非常感谢任何提示。

试图发布代码,但不断收到格式错误,所以放弃了。但无论如何都要帮助我:)

【问题讨论】:

  • 我认为这是正确的行为,你不能在没有OrderBy 的情况下使用ThenBy => dataset.OrderBy().ThenBy()
  • 我不会在服务器端进行多重排序,而是从服务器获取结果,然后在本地进行排序:dbContext.Items.Where(item => item.ID < 20).AsEnumerable().OrderBy(item => item.LastName).ThenBy(item => item.FirstName)。数据库最大的性能损失是仅过滤掉当前相关的数据。如果这已经在服务器端完成,那么在客户端排序就很容易了。
  • Kien Chu 你是对的,但我不知道如何在 dbquery 语句中包含 func。例如,我编写的返回 IQueryable 的方法可以像原生 linq 扩展一样使用。在这种情况下,我可以编写 var output = _db.MyTable.MultiSort("field1,field2:desc").ToArray();
  • 实验我试过这个,q = q.OrderBy(x => MultipleSorts(sortBy));并收到此错误,LINQ to Entities 无法识别方法 'System.Func2[System.Linq.IQueryable1[ORMModel.v_Brand],System.Linq.IOrderedQueryable`1[ORMModel.v_Brand]] MultipleSorts[v_Brand](System.String)'方法,并且该方法不能翻译成商店表达式。
  • 以防万一其他人来寻找多级排序,我发现此代码更易于使用。 aonnull.blogspot.com/2010/08/…

标签: linq func


【解决方案1】:

如果您使用方法语法,您会经常看到 func,例如在WhereGroupByJoin 等中

每个带有一些输入参数和一个返回值的方法都可以转换为Func<...>,如下所示

MyReturnType DoSomething(ParameterType1 p1, ParameterType2, p2) {...}

Func<ParameterType1, ParameterType2, MyReturnType> myFunc = (x, y) => DoSomething(x, y);

Func&lt;ParameterType1, ParameterType2, MyReturnType&gt; 部分的意思是:一个有两个输入参数和一个返回值的函数。输入参数的类型为ParameterType1ParameterType2,按此顺序排列。返回值为MyReturnType

您使用 lambda 表达式实例化 Func&lt;ParameterType1, ParameterType2, MyReturnType&gt; 的对象。在=&gt; 之前键入输入参数的声明,在=&gt; 之后使用这些输入参数调用函数。如果您有多个输入参数,请将它们用括号括起来以逗号分隔。

对于Where,您需要Func&lt;TSource, bool&gt;。所以一个函数有一个源元素作为输入,结果是一个布尔值:

Where(x => x.Name == "John Doe")

对于 GroupJoin,您需要 Func&lt;TOuter,System.Collections.Generic.IEnumerable&lt;TInner&gt;,TResult&gt; resultSelector 类型的 resultSelector

所以这是一个以外部序列的一个元素和内部序列的元素序列作为输入的函数。例如,查询教师和学生:

var result = Teachers.GroupJoin(Students,
    teacher => teacher.Id,           // from every Teacher take the Id,
    student => student.TeacherId,    // from every Student take the TeacherId,
    (teacher, students) => new
    {
        Id = teacher.Id,
        Name = teacher.Name,
        Students = students.Select(student => new
        {
            Id = student.Id,
            Name = student.Name,
        })
        .ToList(),
    });

在这里您可以看到几个 Funcs。 TOuter 是 Teacher,TInner 是 Student,TKey 是 int

  • OuterKeySelector:Func&lt;TOuter, TKey&gt;:teacher => teacher.Id
  • InnerKeySelector: Func&lt;TInner, TKey&gt;: student => student.TeacherId
  • 结果选择器:Func&lt;Touter, IEnumerable&lt;TInner&gt;, TResult&gt;

resultSelector 是一个函数,它接受一个 TOuter(教师)和一系列 TInner(该教师的所有学生)并使用输入参数创建一个对象

(teacher, students) => new {... use teacher and students }

在创建 lambda 表达式时,如果您使用复数来指代集合(教师、学生)和单数(如果您指代集合的一个元素(学生)),通常会很有帮助。

使用=&gt; 开始定义函数。您可以使用=&gt; 之前定义的输入参数来定义=&gt; 之后的结果

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-06
    • 2014-10-23
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    相关资源
    最近更新 更多