EF匿名对象查询返回空集合而不是空集合

时间:2013-05-15 14:55:18

标签: entity-framework collections nullreferenceexception anonymous fixup

我正在使用这个技巧来执行带有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();

1 个答案:

答案 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>();,如果您愿意的话)。