首页 > 解决方案 > 实体框架 - 通过虚拟关键字延迟加载 - 检测循环引用

问题描述

如果集合标记有虚拟关键字(用于代理)并且在上下文中启用了延迟加载,实体框架会在后台延迟加载集合。例如:

public class Entity()
{
    public virtual ICollection<OtherEntity> OtherEntities { get; set; }
}

即使从数据库中获取它的相关方法没有此实体的包含,EF 也会加载 OtherEntities。

知道它会导致序列化问题并将大量不必要的数据加载到创建的结果中,从而覆盖序列化程序中的内容,我开始删除虚拟关键字并在相关存储库中添加包含,但我们仍然倾向于每隔一段时间就会出现可怕的循环引用问题与创建的结果。一些实体内部可能有数十个集合,因此很难调试,它甚至不会抛出异常,而只是在实体之间循环消耗越来越多的内存。我被迫手动追踪它开始循环的位置。这很耗时,而且非常不好玩。知道是否有更好的方法来本地化导致序列化问题的集合?

与 99% 的 .net 项目一样,我们使用 newtonsoft 进行序列化。

标签: c#.netentity-frameworkentity-framework-6

解决方案


virtual首先,您可以通过配置禁用延迟加载,并在您想要使用延迟加载的情况下单独保留属性:

dbContext.Configuration.LazyLoadingEnabled = false;

其次,延迟加载并不是循环引用的唯一问题——如果从数据库中分别检索到它们的导航属性/集合的内容,EF 将连接任何被跟踪的实体(这就是你在之后遇到“偶尔”问题的原因删除所有virtual关键字。

您可以将循环引用的一侧配置为不序列化(例如ScriptIgnoreAttribute),但这将始终阻止序列化(例如,如果您忽略OtherEntity.Entity以便可以在Entity没有循环引用的情况下序列化对象图,它将阻止您OtherEntity.Entity在序列化OtherEntity对象图时包含)。

另一种选择是创建一个单独的视图模型(或数据传输对象)来控制数据的序列化方式。

然后是序列化格式规范,通过仅包含特别请求的引用数据(例如ODataJSON-API)来完全避免该问题。JSON-API 也只在整个响应中包含每个对象一次。


推荐阅读