问题描述
假设我们在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