简体   繁体   English

Linq 字符串。加入组值

[英]Linq string.Join group values

I have the following query and I would like to get a comma seperated list of Locs in the property LValues.我有以下查询,我想在属性 LValues 中获取逗号分隔的 Locs 列表。

from sci in sit

  join i in it on sci.ItemId equals i.Id into it
    from i in it.DefaultIfEmpty()
  join sc in sc on sci.ISId equals sc.Id
  join l in Loc on sc.Id equals l.ESId

  group new { l, sci, i } by new { i.Code, i.Name  } into g
  select new 
  {
      Code = g.Key.Code,
      Name = g.Key.Name ?? "UNKNOWN",
      LValues = string.Join(',', g.Select(x=>x.l.LValue).Distinct()), // This is not working
      Qty = g.Sum(x => x.sci.Qty)
  }

I'm using EF Core 3.1.3 and Linq says我正在使用 EF Core 3.1.3 和 Linq 说

InvalidOperationException: The LINQ expression '(GroupByShaperExpression: KeySelector: new { Code = (i.Code), Name = (i.Name), }, ElementSelector:new { l = (EntityShaperExpression: EntityType: Loc ValueBufferExpression: (ProjectionBindingExpression: l) IsNullable: False ), sci = (EntityShaperExpression: EntityType: Sit ValueBufferExpression: (ProjectionBindingExpression: sci) IsNullable: False ), i = (EntityShaperExpression: EntityType: It ValueBufferExpression: (ProjectionBindingExpression: i) IsNullable: True ) } ).Select(x => xlLValue)' could not be translated. InvalidOperationException: LINQ 表达式'(GroupByShaperExpression: KeySelector: new { Code = (i.Code), Name = (i.Name), }, ElementSelector:new { l = (EntityShaperExpression: EntityType: Loc ValueBufferExpression: (ProjectionBindingExpression: l) IsNullable: False ), sci = (EntityShaperExpression: EntityType: 坐 ValueBufferExpression: (ProjectionBindingExpression: sci) IsNullable: False), i = (EntityShaperExpression: EntityType: It ValueBufferExpression: (ProjectionBindingExpression: i) IsNullable: True ) } ).Select(x => xlLValue)' 无法翻译。 Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估。 See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.有关详细信息,请参阅https://go.microsoft.com/fwlink/?linkid=2101038

If I use an aggregate function like g.Max(x=>xlLValue) it gives one value as expected.如果我使用像 g.Max(x=>xlLValue) 这样的聚合 function 它会按预期给出一个值。 Is there any other way than using client side evaluation?除了使用客户端评估之外,还有其他方法吗? However I have tried string.Join(',', g.Select(x=>xlLValue).ToList().Distinct()) but that didn't work either, throws the same error.但是我尝试string.Join(',', g.Select(x=>xlLValue).ToList().Distinct())但这也不起作用,抛出了同样的错误。

Update更新

It throws the same error even with LValues = g.Select(x=>xlLValue) or LValues = g .即使使用LValues = g.Select(x=>xlLValue)LValues = g也会引发相同的错误。 There must be something in my data or the group by that makes it fail.我的数据或组中必须有一些东西使它失败。

Generated SQL (Sql Server) looks like this using LValues = g.Max(x=>xlLValue) in linq:在 linq 中使用LValues = g.Max(x=>xlLValue)生成的 SQL(Sql Server)看起来像这样:

SELECT [i0].[Code], COALESCE([i0].[Name], N'UNKNOWN') AS [Name],
    MAX([l].[LValue]) AS [LValues], SUM([i].[Qty]) AS [Qty]
FROM [Sit] AS [i]
LEFT JOIN [It] AS [i0] ON [i].[ItemId] = [i0].[Id]
INNER JOIN [Sc] AS [i1] ON [i].[ISId] = [i1].[Id]
INNER JOIN [Loc] AS [l] ON [i1].[Id] = [l].[ESId]
GROUP BY [i0].[Code], [i0].[Name]

I hope this helps understand what is causing the error.我希望这有助于了解导致错误的原因。

I would say you need to materialize your data and concatenate string on client side, cause EF can not translate string.Join into proper SQL:我会说您需要在客户端实现数据并连接字符串,因为 EF 无法转换字符串。加入正确的string.Join

var query = from sci in sit

  join i in it on sci.ItemId equals i.Id into it
    from i in it.DefaultIfEmpty()
  join sc in sc on sci.ISId equals sc.Id
  join l in Loc on sc.Id equals l.ESId

  group new { l, sci, i } by new { i.Code, i.Name  } into g
  select new 
  {
      Code = g.Key.Code,
      Name = g.Key.Name ?? "UNKNOWN",
      LValues = g.Select(x=>x.l.LValue).Distinct(), 
      Qty = g.Sum(x => x.sci.Qty)
  };

var result = query.ToList()
  .Select(o => new
  {
      LValues = string.Join(",", o.LValues)
  });

I think you'll have to do the grouping in memory as EF Core can only do basic aggregate functions in a select when using a group by我认为您必须在 memory 中进行分组,因为 EF Core 在使用 group by 时只能在 select 中执行基本聚合函数

(from sci in sit
join i in it on sci.ItemId equals i.Id into it
from i in it.DefaultIfEmpty()
join sc in sc on sci.ISId equals sc.Id
join l in Loc on sc.Id equals l.ESId
select new 
{
    i.Code,
    i.Name,
    l.LValue,
    sci.Qty
})
.AsEnumerable()
.GroupBy(x => new { x.Code, x.Name })
.Select(grp => new
{
    Code = grp.Key.Code,
    Name = grp.Key.Name ?? "UNKNOWN",
    LValues = string.Join(',', grp.Select(x=>x.LValue).Distinct()), 
    Qty = g.Sum(x => x.Qty)
});

I switched from query syntax to method to better show what is done in the DB and what is done in memory but you can use either syntax through out.我从查询语法切换到方法,以更好地显示在数据库中完成了什么以及在 memory 中完成了什么,但是您可以使用任何一种语法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM