查看官方 EF Core 文档,了解有关 Complex Query Operators: GroupBy 的一般信息。
由于没有数据库结构可以表示 IGrouping,因此 GroupBy 运算符在大多数情况下没有翻译。当聚合运算符应用于每个返回标量的组时,可以将其转换为关系数据库中的 SQL GROUP BY。 SQL GROUP BY 也有限制。它要求您仅按标量值进行分组。投影只能包含分组键列或应用于列的任何聚合。 EF Core 识别此模式并将其转换为服务器 [...]
现在,对于您的具体示例,它可以正常工作。下面是一个示例控制台项目来证明:
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class OrderLine
{
[Key]
public int OrderLineId { get; set; }
public int ItemId { get; set; }
public int Qty { get; set; }
}
public class Supplier
{
[Key]
public int SupplierId { get; set; }
public string Name { get; set; }
}
public class Item
{
[Key]
public int ItemId { get; set; }
public int SupplierId { get; set; }
}
public class Context : DbContext
{
public DbSet<OrderLine> OrderLines { get; set; }
public DbSet<Supplier> Suppliers { get; set; }
public DbSet<Item> Items { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So63040380")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<OrderLine>()
.HasData(
new OrderLine {OrderLineId = 1, ItemId = 1, Qty = 100},
new OrderLine {OrderLineId = 2, ItemId = 2, Qty = 42},
new OrderLine {OrderLineId = 3, ItemId = 3, Qty = 21});
builder.Entity<Supplier>()
.HasData(
new Supplier {SupplierId = 1, Name = "Supplier A"},
new Supplier {SupplierId = 2, Name = "Supplier B"});
builder.Entity<Item>()
.HasData(
new Item {ItemId = 1, SupplierId = 1},
new Item {ItemId = 2, SupplierId = 1},
new Item {ItemId = 3, SupplierId = 2});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var supplierNameAndQuantity = (from line in context.OrderLines
join item in context.Items on line.ItemId equals item.ItemId
join supplier in context.Suppliers on item.SupplierId equals supplier.SupplierId
group line by supplier.Name into lineGrouping
select new {Name = lineGrouping.Key, Qty = lineGrouping.Sum(x => x.Qty)})
.ToList();
Debug.Assert(supplierNameAndQuantity.Count == 2);
Debug.Assert(supplierNameAndQuantity[0].Name == "Supplier A");
Debug.Assert(supplierNameAndQuantity[0].Qty == 142);
Debug.Assert(supplierNameAndQuantity[1].Name == "Supplier B");
Debug.Assert(supplierNameAndQuantity[1].Qty == 21);
}
}
}
查询被翻译成以下 SQL,这是正确的:
SELECT [s].[Name], SUM([o].[Qty]) AS [Qty]
FROM [OrderLines] AS [o]
INNER JOIN [Items] AS [i] ON [o].[ItemId] = [i].[ItemId]
INNER JOIN [Suppliers] AS [s] ON [i].[SupplierId] = [s].[SupplierId]
GROUP BY [s].[Name]