选择可选导航属性实体框架的属性的正确方法是什么?
我担心,如果导航属性为空,那么当我尝试访问其(可选导航属性)属性时,将会抛出错误。
这是我尝试过的:
return await this.relatedCasesRepository
.GetAll()
.AsNoTracking()
.Where(rc => rc.FirstCaseId == caseId || rc.SecondCaseId == caseId)
.Select(rc => new RelatedCaseInfoDto
{
FirstCaseId = rc.FirstCaseId,
FirstCaseName = rc.FirstCase.Name,
SecondCaseId = rc.SecondCaseId,
SecondCaseName = rc.SecondCase.Name,
CaseRelationTypeId = rc.CaseRelationTypeId,
CaseRelationTypeName = rc.CasesRelationType?.Name,
Id = rc.Id
})
.ToArrayAsync();
代码:
rc.CasesRelationType?.Name
产生错误:
表达式树 lambda 不能包含空传播运算符。
这是否意味着我应该执行第二个请求来获取可选导航属性的所有属性?或者是否有办法在可选导航属性不为 null 的情况下查询可选导航属性的属性,否则返回 null?
为什么不使用条件运算符?
CaseRelationTypeName = (rc.CasesRelationType != null) ? rc.CasesRealtionType.Name : null;
生成的 SQL 将使用 LEFT JOIN,因此您可以简单地省略空条件参数并编写
CaseRelationTypeName = rc.CasesRelationType.Name,
或者,启用可为空上下文
CaseRelationTypeName = rc.CasesRelationType!.Name,
如果在链接表中找不到条目,这将简单地将
CaseRelationTypeName
设置为 null
。
注意: 启用可为空上下文时,这将为
Name
保留不可空类型(例如字符串),并且您需要手动转换为 string?
,这使得它有点难看(这对于分配工作,但如果目标变量不可为空,则会再次产生可为空的警告 string
):
CaseRelationTypeName = (string?)rc.CasesRelationType!.Name,
这仍然比完整的条件语句短,但有效地将选择归结为口味问题:
CaseRelationTypeName = (rc.CasesRelationType != null)
? rc.CasesRelationType.Name
: null;
启用可为空上下文后,后者将本质上正确地处理可为空类型。
禁用可空上下文后,我看不出采用长版本有任何好处。
以 EF Core 8 作为等效示例,上述所有选项(包括显式条件)都会生成完全相同的 SQL 语句,该语句本质上只是对
Name
列使用 SELECT,对 CasesRelationType
表使用 LEFT JOIN。
对于 EF Core,行为在此处的文档中进行了描述,尽管是在不同的上下文中:
处理可选关系时,可能会遇到编译器警告,而实际的空引用异常是不可能的。在转换和执行 LINQ 查询时,EF Core 保证如果可选的相关实体不存在,则任何指向该实体的导航都将被忽略,而不是抛出异常。但是,编译器不知道此 EF Core 保证,并会生成警告,就好像使用 LINQ to Objects 在内存中执行 LINQ 查询一样。因此,有必要使用 null 宽容运算符 (!) 来通知编译器实际的 null 值是不可能的:[...]