Строка Linq. Значения группы - PullRequest
0 голосов
/ 08 мая 2020

У меня следующий запрос, и я хотел бы получить разделенный запятыми список Locs в свойстве LValues.

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)
  }

Я использую EF Core 3.1.3, а Linq говорит:

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: Sit ValueBufferExpression: (ProjectionBindingExpression: sci) IsNullable: False), i = (EntityShaperExpression: EntityType: It ValueBufferExpression: (i) ) .Select (x => xlLValue) 'не может быть переведен. Либо перепишите запрос в форме, которая может быть переведена, либо явно переключитесь на оценку клиента, вставив вызов либо AsEnumerable (), AsAsyncEnumerable (), ToList (), либо ToListAsyn c (). См. https://go.microsoft.com/fwlink/?linkid=2101038 для получения дополнительной информации.

Если я использую агрегатную функцию, например g.Max (x => xlLValue), она дает одно значение, как ожидалось. Есть ли другой способ, кроме использования оценки на стороне клиента? Однако я пробовал string.Join(',', g.Select(x=>x.l.LValue).ToList().Distinct()), но это тоже не сработало, выдает ту же ошибку.

Обновление

Выдает ту же ошибку даже с LValues = g.Select(x=>x.l.LValue) или LValues = g. В моих данных или в группе должно быть что-то, что приводит к сбою.

Сгенерировано SQL (Sql Сервер) выглядит так, используя LValues = g.Max(x=>x.l.LValue) в linq:

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]

Надеюсь, это поможет понять причину ошибки.

Ответы [ 2 ]

0 голосов
/ 08 мая 2020

Я думаю, вам придется выполнить группировку в памяти, поскольку EF Core может выполнять только базовые c агрегатные функции в выборе при использовании группы

(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)
});

Я переключился с синтаксиса запроса на , чтобы лучше показать, что делается в БД и что делается в памяти, но вы можете использовать любой синтаксис.

0 голосов
/ 08 мая 2020

Я бы сказал, что вам нужно материализовать свои данные и объединить строку на стороне клиента, потому что EF не может преобразовать string.Join в правильный SQL:

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)
  });

...