按可为空导航属性的 属性 分组时如何传播导航属性的空值
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
假设我们在 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