我正在使用这个技巧来执行带有EF的条件包含。 http://blogs.msdn.com/b/alexj/archive/2009/10/13/tip-37-how-to-do-a-conditional-include.aspx
我遇到的问题是任何没有记录的集合都是null,而不是空的。这导致头痛,因为我必须检查每个集合才能在我的mvc视图中循环它,否则我得到一个空引用异常。
例如,StudentModules集合将为null。如何在查询中将其变为空列表?即无需遍历所有并检查。
我可以在poco中放置一个构造函数来初始化列表,修复它,但是这个集合是poco中的虚拟成员(基于EF视频!) - 当然这不是可行的方法吗? / p>
var query = from module in db.Modules
where module.Id == id
select new
{
module,
QualificationModules = from qualificationModule in module.QualificationModules
where qualificationModule.IsDeleted == false
select new
{
qualificationModule,
qualificationModule.Qualification,
StudentModules = from studentModule in qualificationModule.StudentModules
where studentModule.IsDeleted == false
select new
{
studentModule,
studentModule.Student
}
},
Assessments = (from assessment in module.Assessments
where assessment.IsDeleted == false
select new
{
assessment,
assessment.AssessmentType
}
)
};
var modules = query.AsEnumerable().Select(x => x.module);
return modules.ToList().First();
答案 0 :(得分:2)
关系fixup在实体附加到上下文时运行 - 通过调用Attach
手动或者由于查询(您的情况)实体化实体时。
它基于实体的外键并且在两个方向上工作:
如果上下文已包含实体A
,其中外键f
与实体B
并且实体B
附加到具有上下文的上下文与f
中的外键具有相同值A
的主键(即两个实体通过FK关系相关),然后实体框架将执行以下操作:
A
的导航参考属性为B
,则会将附加的实体B
分配给此媒体资源。B
的导航参考属性为A
(一对一关系),则会将A
分配给此媒体资源。B
的导航集合属性为A
(一对多关系),则会将A
添加到附加实体B
中的此集合中。如果集合是null
,它将在添加之前实例化集合。如果实体B
被附加到具有外键f
的上下文到上下文已包含且具有{{1}的实体A
的上下文中作为主键,EF将根据上述相同的规则设置导航属性。
作为旁注:关系修正基于外键的事实(它们总是在查询实体时加载,无论FK是否作为模型类中的属性公开)也是为什么relationship fixup不适用于多对多关系,因为多对多关系中的两个实体没有外键。
现在,如果您的案例中没有相关的f
,则没有StudentModules
实体被加载到上下文中,并且EF没有什么可以针对修正的目标。请记住,fixup算法与特定查询无关,并且不仅修复了此查询将实现的实体之间的关系,而且还将考虑所有实体以进行上下文已包含的修复,无论他们是如何进入这种背景的。如果您希望将集合实例化为空集合,则EF已遍历StudentModule
的所有附加父实体,并且只创建一个空集合。在修复期间执行此操作是没有意义的,而不是在实体附加到上下文之前预先创建空集合。
我可以在poco中放置一个构造函数来初始化列表 修复它,但这个集合是poco中的虚拟成员 (基于EF视频!) - 当然这不是要走的路?
在我看来,如果您不希望在模型类实例中拥有StudentModules
个集合,那么 是最佳解决方案。如果集合声明为null
(以启用延迟加载)并不重要。集合类型没有派生代理类型,只有添加到集合的实例才是派生代理。在这两种情况下,您都可以使用virtual
(或StudentModules = new HashSet<StudentModule>();
,如果您愿意的话)。