linq2db.EntityFrameworkCore icon indicating copy to clipboard operation
linq2db.EntityFrameworkCore copied to clipboard

Extension Aggregate Functions work in "flat" queries, but don't work in nested query

Open Meigyoku-Thmn opened this issue 4 years ago • 4 comments

linq2db already had the StringAggregate extension method, I define one more aggregate method like this:

[Sql.Function("ANY_VALUE", ServerSideOnly = true, IsAggregate = true, ArgIndices = new[] { 0 })]
public static TItem AnyValue<TSource, TItem>(this IEnumerable<TSource> src, Expression<Func<TSource, TItem>> value)
{
    throw new InvalidOperationException();
}

It's excellent that both functions work in simple query like this:

LinqToDBForEFTools.Initialize();

using var db = new NutshellContext();

var yy = (from c in db.Customer
          join p in db.Purchase on c.Id equals p.CustomerId
          group new { c, p } by c.Id into g
          select new {
              CustomerId = g.Key,
              CustomerName = g.AnyValue(e => e.c.Name),
              Des = g.StringAggregate(", ", e => e.p.Description).ToValue(),
          })
          .ToLinqToDB()
          .ToArray()
         ;

(I use the "Nutshell" database from LinqPad) The generated sql is:

SELECT
  `c_1`.`ID`,
  ANY_VALUE(`c_1`.`Name`),
  GROUP_CONCAT(`p`.`Description` SEPARATOR ', ')
FROM
  `customer` `c_1`
          INNER JOIN `purchase` `p` ON `c_1`.`ID` = `p`.`CustomerID`
GROUP BY
  `c_1`.`ID`

But for some reason it failed on subquery:

var zz = (from c in db.Customer
          select new {
              Key = c.Id,
              Subquery = (
                from p in c.Purchase
                group p by p.CustomerId into g
                select new {
                    Tag = g.Key,
                    Sum = g.Sum(p => p.Id),
                    Des = g.AnyValue(p => p.Description),
                    Dess = g.StringAggregate(", ", p => p.Description).ToValue(),
                }).ToArray(),
          })
          .ToLinqToDB()
          .ToArray();

Instead of translating AnyValue and StringAggregate to the corresponding sql function, linq2db always calls into these 2 functions, and of course they throw a not supported exception.

So did I do anything wrong? What is the right way to do this?

Meigyoku-Thmn avatar Mar 16 '21 18:03 Meigyoku-Thmn

Try this one:

[Sql.Extension("ANY_VALUE({value})", ServerSideOnly = true, IsAggregate = true)]
public static TItem AnyValue<TSource, TItem>(this IEnumerable<TSource> src, [ExprParameter] Expression<Func<TSource, TItem>> value)
{
    throw new InvalidOperationException();
}

I have prepared fix for other extensions which avoid unwanted invocations.

sdanyliv avatar Mar 16 '21 19:03 sdanyliv

I just tried your solution and the error is still the same.

Meigyoku-Thmn avatar Mar 16 '21 19:03 Meigyoku-Thmn

Ok, will check what happened. Thanks for reporting.

sdanyliv avatar Mar 16 '21 19:03 sdanyliv

Forgot to tell you, I use Entity Framework Core 3.1.13, .NET Core 3.1 and linq2db.EntityFrameworkCore 3.9.6 (The lastest version that can work with EF Core 3.1).

Meigyoku-Thmn avatar Mar 17 '21 02:03 Meigyoku-Thmn