按可为空导航属性的 属性 分组时如何传播导航属性的空值

How to propagate the null value of a navigation propety when grouping by a property of a nullable navigation propety

假设我们在 EfCore 中有这些实体...

public class Entity
{
    public int Id { get; set; }
    public decimal Rate { get; set; }
    // ... omitted for brevity
    public int? NavigationPropertyId { get; set; }
    public NavigationProperty? NavigationProperty { get; set; }
    // ... omitted for brevity
}

public class NavigationProperty
{
    public int Id { get; set; }
    public int AnotherNavigationPropertyId { get; set; }
    // ... omitted for brevity
}

...并且我们想要获得具有相同 AnotherNavigationProperty.[=19= 的 Entities 平均值 Rate ]

我尝试的 efcore 查询抛出“System.InvalidOperationException:可空对象必须有一个值”。

from entity in _context.Entities
group entity by entity.NavigationProperty.AnotherNavigationPropertyId 
    into entitiesByAnotherNavigationProperty
orderby entitiesByAnotherNavigationProperty.Key
select new 
{
    AnotherNavigationPropertyId = entitiesByAnotherNavigationProperty.Key,
    AverageRate = entitiesByAnotherNavigationProperty.Average(a => a.Rate)
}

我知道它在查询 returns

中被 EfCore 成功地 t运行 指定为 ToQueryString()
SELECT [p].[AnotherNavigationPropertyId], AVG([a].[Rate]) AS [AverageRate]
FROM [Entities] AS [a]
LEFT JOIN [NavigationProperties] AS [p] ON [a].[NavigationPropertyId] = [p].[Id]
GROUP BY [p].[AnotherNavigationPropertyId]
ORDER BY [p].[AnotherNavigationPropertyId]

哪个正确 returns 我需要的结果 运行 在数据库上

如何提示 EfCore 传播空导航 属性? (因为表达式树不能包含空传播 ?. 运算符)

这是因为 C# 和 SQL 空语义之间的差异。

在 SQL 查询中每个值都可以是 null,即使源列不允许 null。事实上,没有可空或不可空类型之类的东西,只有 not null 约束。在 LINQ 查询中,可空性由 属性.

的静态类型决定

不久,我们在 CLR 和 SQL 查询值类型之间发生了冲突。为了解决它,您必须让 CLR 知道表达式类型实际上是可以为 null 的,即使它的推断 CLR 类型不是。由于表达式树中不允许使用 ?.,因此您必须为此使用 cast 运算符。唯一的缺点是你需要知道确切的 属性 类型(不能使用正常的类型推断)。

话虽如此,在问题的示例查询中,只需在此处添加 int? cast

group entity by (int?)entity.NavigationProperty.AnotherNavigationPropertyId