【问题标题】:get error when use first() after goupby()在 groupby() 之后使用 first() 时出错
【发布时间】:2022-12-28 18:09:08
【问题描述】:

我有两个这样的表:

CREATE TABLE [dbo].[Transactions](
    [Id] uniqueidentifier NOT NULL,
    [CustomerId] uniqueidentifier NOT NULL, // equals to AspNetUsers.Id
    [CoinId] uniqueidentifier NOT NULL,
    [Amount] [decimal](18, 8) NOT NULL,
    [Balance] [decimal](18, 8) NOT NULL,
    [CreatedOn] [datetime2](7) NOT NULL
)

CREATE TABLE [dbo].[AspNetUsers](
    [Id] uniqueidentifier NOT NULL,
    [FullName] nvarchar(256) NOT NULL
)

CREATE TABLE [dbo].[Coins](
    [Id] uniqueidentifier NOT NULL,
    [Name] nvarchar(256) NOT NULL
)

我想创建一个报告,显示每个客户有多少余额。 我的 linq 查询是:

var q = (from t in _db.Transactions
         join u in _db.Users on t.CustomerId equals u.Id
         group t by new { t.CustomerId, u.FullName } into grp
         where grp.OrderByDescending(c => c.CreatedOn).Select(c => c.Balance).First() > 0
         select new  
         {
            CustomerId = grp.Key.CustomerId,
            CustomerFullName = grp.Key.FullName,
            Balance = grp.OrderByDescending(c => c.CreatedOn).Select(c => c.Balance).FirstOrDefault()
         });

var balances = q.ToList();

此查询在 linqpad 中正常,但在项目(aspnet core 3.1 - netstandard2.1(我的查询层) - Microsoft.EntityFrameworkCore 版本 5.0.12)中出现以下错误:

The LINQ expression 'GroupByShaperExpression:
KeySelector: new { 
    CustomerId = t.CustomerId, 
    FullName = a.FullName
 }, 
ElementSelector:EntityShaperExpression: 
    EntityType: Transaction
    ValueBufferExpression: 
        ProjectionBindingExpression: EmptyProjectionMember
    IsNullable: False

    .OrderByDescending(c => c.CreatedOn)' could not be translated. Either rewrite the query in a 
form that can be translated, or switch to client evaluation explicitly by inserting a call to 
'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
 See https://go.microsoft.com/fwlink/?linkid=2101038 for more information. 

【问题讨论】:

  • 这实际上取决于使用的 EFC 版本。您在标签中指定了 3.1,在问题中指定了 5.0,那么您究竟针对哪一个(请更正标签和/或问题)?但如果它有帮助,我能说的是,在 3.1 中你没有机会(不支持翻译),在 5.x 中 - 不确定,可能不会,在 6.0 中似乎有效。
  • 似乎 ef 无法处理组中的 First() 。 alternane 解决方案是使用子查询来实现结果
  • 请指定模型类,尤其是导航属性。
  • 用户与交易具有一对一关系(Users.Id <> Transactions.CustomerId),硬币与交易具有一对多关系
  • 使用模型类更新问题。

标签: group-by entity-framework-core linq-to-entities ef-core-5.0


【解决方案1】:

最后我意识到 ef 无法处理 group by 和 First(),所以我尝试使用另一种策略。

解决方案是使用子查询而不是分组。这是查询:

var query = 
(from x in
   (from u in Users
    select new 
    {
      CustomerId = u.Id,
      CustomerFullName = u.FullName,
      LastTransaction = (from t in Transactions
                        join c in Coins on t.CoinId equals c.Id
                        where t.CustomerId == u.Id
                        orderby t.CreatedOn descending
                        select new { t.Balance, CoinSymbol = (string)c.Symbol, CoinId = c.Id, CoinName = (string)c.Name }).FirstOrDefault()
    })
select new 
{ 
    Balance = x.LastTransaction == null ? 0 : x.LastTransaction.Balance,
    x.CustomerId, 
    x.CustomerFullName, 
    CoinSymbol = x.LastTransaction == null ? null : x.LastTransaction.CoinSymbol,
    CoinName = x.LastTransaction == null ? null : x.LastTransaction.CoinName,
    CoinId = x.LastTransaction == null ? default(Guid) : x.LastTransaction.CoinId
});

var result = query
.Where(l => l.CoinSymbol != null && l.CoinSymbol == "USDT")
.Select(l => new 
{
    l.CustomerId, 
    TotalBalance = l.Balance,
    l.CustomerFullName, 
    l.CoinSymbol,
    l.CoinName,
    l.CoinId
}).ToList();

如您所见,我从用户表开始,从 transactions 表中添加一个子查询选择部分并检查可空值。

最后我只是使用“查询”来添加一些额外的条件

  • “(string)”上方查询中的字符串显式转换是因为 Coin.Name 和 Coin.Symbol 是 ValueObjects,为了正确获取它们,我必须将它们显式转换为字符串

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-08
    • 2017-12-14
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-26
    相关资源
    最近更新 更多