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

问题描述

假设我们在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
}

...,我们希望获得Rate中具有相同Entities平均值 AnotherNavigationProperty

我尝试的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)
}

我知道EfCore在查询返回时已成功将其翻译为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]

在数据库上运行时,哪个可以正确返回我需要的结果

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

解决方法

这是由于C#和SQL空语义之间的差异。

在SQL查询中,即使源列不允许null,每个值也可以是null。实际上,不存在诸如可为空或不可为空的类型之类的东西,只是not null约束。在LINQ查询中,可为空性由属性的静态类型确定。

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

话虽如此,在问题的样本查询中,只需在此处添加int?强制转换

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

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...