【问题标题】:'Client side GroupBy is not supported.' [duplicate]'不支持客户端 GroupBy。' [复制]
【发布时间】:2020-08-26 05:31:36
【问题描述】:

我正在尝试在北风数据库中运行 GroupBy() 命令,这是我的代码

using(var ctx = new TempContext())
{
    var customer = (from s in ctx.Customers
                    group s by s.LastName into custByLN
                    select custByLN);
    foreach(var val in customer)
    {
        Console.WriteLine(val.Key);
        {
            foreach(var element in val)
            {
                Console.WriteLine(element.LastName);
            }
        }
    }
}

它给了System.InvalidOperationException: 'Client side GroupBy is not supported'

【问题讨论】:

  • 我猜这正在变成一个组加入,这是一个 LINQ 的事情。

标签: entity-framework linq entity-framework-core


【解决方案1】:

显然,您正在尝试使客户组的姓氏具有相同的值。一些数据库管理系统不支持 GroupBy,尽管这种情况很少见,因为 Grouping 是一种非常常见的数据库操作。

要查看您的数据库管理系统是否支持分组,请尝试使用 GroupBy 方法语法。以ToList结尾,执行GroupBy:

var customerGroupsWithSameLastName = dbContext.Customers.GroupBy(

    // Parameter KeySelector: make groups of Customers with same value for LastName:
    customer => customer.LastName)
.ToList();

如果这可行,那么与您的 DbContext 通信的 DBMS 将接受 GroupBy。

结果是组列表。每个 Group 对象都实现了IGrouping<string, Customer>,这意味着每个 Group 都有一个 Key:该组中所有客户的公共 LastName。该组是(没有)具有此姓氏的所有客户的序列。

顺便说一句:GroupBy 的一个更有用的重载有一个额外的参数:resultSelector。使用 resultSelector 您可以影响输出:它不是IGrouping 对象的序列,而是您使用函数指定的对象序列。

这个函数有两个输入参数:共同的姓氏和所有具有这个姓氏值的客户。此函数的返回值是您的输出序列的元素之一:

var result = dbContext.Customers.GroupBy(
    customer => customer.LastName,

    // parameter resultSelector: take the lastName and all Customers with this LastName
    // to make one new:
    (lastName, customersWithThisLastName) => new
    {
        LastName = lastName,
        Count = customersWithThisLastName.Count(),

        FirstNames = customersWithThisLastName.Select(customer => customer.FirstName)
                                              .ToList(),
        ... // etc
    })
    .ToList();

回到你的问题

如果上面的代码显示您的 DBMS 不支持该功能,您可以让您的本地进程进行分组:

var result = dbContext.Customer
    // if possible: limit the number of customers that you fetch
    .Where(customer => ...)

    // if possible: limit the customer properties that you fetch
    .Select(customer => new {...})

    // Transfer the remaining data to your local process:
    .AsEnumerable()

    // Now your local process can do the GroupBy:
    .GroupBy(customer => customer.LastName)
    .ToList();

由于您选择了完整的客户,所有客户数据无论如何都会被传输,因此如果您让本地进程执行 GroupBy 并不会造成太大损失,除了 DBMS 可能更优化以更快地进行分组您的本地进程。

警告:数据库管理系统在选择数据方面进行了极大优化。数据库查询中较慢的部分之一是将所选数据从 DBMS 传输到本地进程。因此,如果您必须使用AsEnumerable(),您应该意识到您将传输到现在为止选择的所有数据。确保在AsEnumerable() 之后不转移任何你不会使用的东西;所以如果你只对FirstNameLastName感兴趣,不要传输主键、外键、地址等。让你的DBMS做Where and Select`

【讨论】:

  • FirstNames = customersWithThisLastName.Select(customer => customer.FirstName) .ToList(),当我通过调试看到客户的价值时,这条语句似乎不起作用,它有 lastname=count = 3 这些它不生成名称列表的值类型
  • 很好的解释,但你肯定有问题!它说不支持“客户端”分组。并不是说 DBMS 做不到。我知道我的 DBMS、SQL Server 和 Postgres 都可以,但我仍然收到这个错误,这似乎是因为我在查询中做了一些事情来强制它在客户端上进行分组。
猜你喜欢
  • 2020-04-07
  • 1970-01-01
  • 2018-02-10
  • 1970-01-01
  • 2020-12-14
  • 1970-01-01
  • 1970-01-01
  • 2015-04-08
  • 2020-08-11
相关资源
最近更新 更多