Entity framework EF匿名对象查询返回空集合而不是空集合
我用这个技巧用EF执行条件Include 我遇到的问题是,任何没有记录的集合都是空的,并且不是空的。这让人头疼,因为我必须先检查每个集合,然后才能在mvc视图中循环使用它,否则会出现空引用异常 例如,StudentModules集合将为null。如何在查询中将其转换为空列表?ie,而无需对其进行循环检查 我可以在poco中放置一个构造函数来初始化列表,这会修复它,但是这个集合是poco中的一个虚拟成员(基于EF视频!)-当然不是这样做的吗Entity framework EF匿名对象查询返回空集合而不是空集合,entity-framework,collections,nullreferenceexception,anonymous,fixup,Entity Framework,Collections,Nullreferenceexception,Anonymous,Fixup,我用这个技巧用EF执行条件Include 我遇到的问题是,任何没有记录的集合都是空的,并且不是空的。这让人头疼,因为我必须先检查每个集合,然后才能在mvc视图中循环使用它,否则会出现空引用异常 例如,StudentModules集合将为null。如何在查询中将其转换为空列表?ie,而无需对其进行循环检查 我可以在poco中放置一个构造函数来初始化列表,这会修复它,但是这个集合是poco中的一个虚拟成员(基于EF视频!)-当然不是这样做的吗 var query = from module in d
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();
当一个实体被附加到上下文时,关系修复将运行—可以通过调用
Attach
手动执行,也可以通过查询(您的案例)将该实体具体化
它基于实体的外键并在两个方向上工作:
- 如果上下文已经包含一个实体
,该实体具有一个外键A
到实体f
,并且一个实体B
被附加到上下文,该上下文的主键与B
中的外键具有相同的值A
(即,两个实体通过FK关系关联)然后实体框架将执行以下操作:f
- 如果
具有指向A
的导航引用属性,它将为该属性分配附加的实体B
B
- 如果
具有指向B
(一对一关系)的导航引用属性,则将a
分配给该属性a
- 如果
具有指向B
(一对多关系)的导航集合属性,则将a
添加到附加实体a
中的该集合中。如果集合为B
,它将在添加之前实例化集合null
- 如果
- 如果实体
被附加到具有外键B
的上下文,而实体f
则上下文已经包含并且具有a
作为主键,则EF将基于上述相同规则设置导航属性f
StudentModules
,那么就没有加载到上下文中的StudentModule
实体,EF也没有什么可以用于修复的目标。请记住,固定算法与特定查询无关,并且不仅修复了该查询将实现的实体之间的关系,而且考虑到上下文如何包含,所有的实体都会考虑上下文是否已包含,而不管它们是如何进入上下文的。如果希望集合被实例化为空集合,则EF已通过StudentModules
的所有附加父实体运行,并仅创建一个空集合。在修复过程中这样做而不是在实体连接到上下文之前创建空集合是没有意义的
我可以在poco中放置一个构造函数来初始化列表,这
修复了它,但此集合是poco中的虚拟成员
(基于EF视频!)-这肯定不是一条路吗
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();
在我看来,如果您不希望模型类实例中有
null
集合,那么是最好的解决方案。集合是否声明为virtual
(以启用延迟加载)并不重要。集合类型没有派生代理类型,只有添加到集合中的实例是派生代理。在这两种情况下,您都可以使用StudentModules=newhashset()代码>(或列表
,如果您愿意)。aaaaaah,我明白了,很好的解释。非常彻底。谢谢你。这个算法最大的问题是它使实体是否没有子实体或者它们是否没有被加载变得模糊不清。其中一个可能是编程错误(忘记立即加载),而另一个是有效的系统状态。在许多web场景中,延迟加载很可能是一种体系结构反模式,并在上下文级别故意禁用,因为您希望确保数据库服务器和web服务器之间只发生一次往返。是否有其他方法可以推断相关实体(集合或单个引用)是否已加载?@Marchy:我认为唯一可靠的模式是:if(!context.Entry(parent).reference(p=>p.Child).IsLoaded)context.Entry(parent).reference(p=>p.Child).Load()
(或.collection(p=>p.Children)
用于收藏)。但是,它可能会生成不必要的查询,因为IsLoaded
可能返回false
,尽管由于之前的一些查询,所有相关实体都已附加。EF将检测到这一点,但仅在.Load()
触发器的查询返回结果后。