How to perform multiple aggregates without a group by clause?
- Dominant language
- C#
- Stars
- 14.8k
- Forks
- 3.4k
- PR merge metrics
- PR metrics pending
Description
Consider the following query:
``` c#
from t in db.Table
group (int?)t.Value by 1 into tg
select new
{
A = tg.Max(),
B = tg.Count()
C = tg.Sum()
}
```
EFC5 translation:
```sql
SELECT MAX(m.Value) AS A, COUNT(m.Value) AS B, COALESCE(SUM(m.Value), 0) AS C
FROM Table AS m
```
EFC6 translation:
```sql
SELECT MAX(t.Value) AS A, COUNT(*) AS B, COALESCE(SUM(m.Value), 0) AS C
FROM
(
SELECT m.Value, 1 AS Key
FROM Table AS m
) AS t
GROUP BY t.Key
```
When the table (i.e. source being aggregated) is empty the EFC5 query returns `(NULL, 0)`, the EFC6 query returns no rows.
Considering that EFC6 behavior matches the in-memory Enumerable behavior I guess this breaking change is intentional. However I would still need a mechanism to aggregate (without a `GROUP BY` clause) that always returns exactly 1 row whether the source is empty or not. How can I express this in LINQ?
This
```c#
from t in db.Table.DefaultIfEmpty()
group (int?)...
```
returns bad data: `(NULL, 1)`
This
```c#
(from t in ...
).DefaultIfEmpty()
```
throws an exception:
```
System.InvalidOperationException: Nullable object must have a value.
at lambda_method97(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Program.Main()
```
### Include your code
```csproj
Exe
net6.0
```
```c#
class Program
{
public class Table
{
public int Id { get; set; }
public int? Value { get; set; }
}
public class TestDb : DbContext
{
public DbSet Table { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("data source=dummy");
}
}
static void Main()
{
using var db = new TestDb();
var q = from t in db.Table
group (int?)t.Value by 1 into tg
select new
{
A = tg.Max(),
B = tg.Count(),
C = tg.Sum(),
};
var items = q.ToList();
}
}
```
### Include provider and version information
EF Core version: 6.0.1
Database provider: Microsoft.EntityFrameworkCore.SqlServer 6.0.1
Target framework: .NET 6.0
Operating system: Windows 10 21H1
IDE: Visual Studio 2022 17.0.4
Contributor guide
Assessment
This issue has not been assessed yet.