我需要使用实体框架在 C# 项目中执行 10 个左联接。我已经检查了至少 10 个不同的页面和堆栈溢出帖子,了解如何执行此操作。他们都没有工作。
我当前的联接如下所示:
from tbl1 in context.tblName1
join varOne in context.tblName2 on tbl1.paramOne equals varOne.paramOne into j1
from jResOne in j1.DefaultIfEmpty()
我收到错误消息:
"强制转换为值类型'System.Int32'失败,因为具体化值为 null - 结果类型的泛型参数或查询必须使用可为 null 的类型。">
我被引导相信应该通过".DefaultIfEmpty()">
如何解决此问题?
@David Browne 关于 EF 中的导航属性与联接是正确的。但这里的问题是不同的(与连接操作无关,但与处理结果无关),并且包含在异常消息中:
强制转换为值类型"System.Int32"失败,因为具体化值为null - 结果类型的泛型参数或查询必须使用可为 null 的类型。
这意味着投影 (select
) 试图从左侧外连接的某些右侧分配一个不可为空的类型值。在 LINQ to Objects 中,这将是一个简单的NullReferenceException
。但是,LINQ to Entities 将查询转换为 SQL,数据库(尤其是 SQL)自然支持NULL
值,即使对于不可为空的列也是如此。因此,EF 能够成功执行 SQL,但是当涉及到需要具体化结果(即将其放入匿名/特定类成员)时,db 查询返回null
而相应的属性是不可为空的类型,EF 无法继续并引发异常,要求您通过将其转换为可为空的类型来解决它, 或将其转换为某个默认值等 - 这取决于你,EF 无法做出该决定。
假设TableB
有int Property
,并且您有一个这样的查询:
var query = from a in db.TableA
from b in db.TableB.Where(b => b.Key == a.Key).DefaultIfEmpty()
select new { Property = b.Property };
结果Property
的 C# 隐含类型是int
,因此当查询结果包含与a
不匹配的b
时,您将获得上述异常(从 C# 的角度来看,b
null
,但从 SQL 方面b.Property
将是NULL
)。
为了解决它,您可以将其提升为可为空的类型:
Property = (int?)b.Property
或某个默认值
Property = b != null ? b.Property : 0
根据您的需求。并且对任何不可为空的值类型(如int
、decimal
、DateTime
等)执行类似的操作(string
是一个引用类型,所以它没有这样的问题(可以保存null
值))。
需要使用实体框架在 C# 项目中执行 10 个左联接
这是极不可能的。 在 LINQ 中使用导航属性而不是联接向实体表示查询几乎总有一种更好、更简单的方法。
相反,只需在导航属性中导航以投影相关值。