EF 6禁用延迟加载,但子记录仍加载

4

我正在使用EF6 Code First。有两个表,LessonLessonSectionsLessonSections表有一个外键指向Lesson.Id

这是已删除非重要字段的Lesson类:

public partial class Lesson
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Lesson()
    {
        LessonSections = new HashSet<LessonSection>();
    }

    [StringLength(50)]
    public string Id { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<LessonSection> LessonSections { get; set; }
}

这是我如何初始化我的数据模型:

    var db = new Touch_Type_Trainer_DB.DataModel();
    db.Configuration.ProxyCreationEnabled = false;
    db.Configuration.LazyLoadingEnabled = false;

在我第一次调用数据库来检索数据库中的第一课时后,结果对象没有LessonSections

Before second call

然后我进行第二次调用,将章节检索到一个单独的对象中。(它们必须在单独的对象中,因为我想将它们序列化为JSON字符串,如果使用标准的EF LazyLoading,序列化程序会在LessonLessonSections之间的循环引用上停止。)

After second call

现在我的原始对象从数据库中加载了两个部分,即使我从未访问过LessonSections属性,即使LazyLoadingEnabled设置为False!

为什么会加载LessonSections

编辑:

我正在使用Newtonsoft将对象序列化为JSON字符串。也许在Newtonsoft中有一个配置设置,我应该设置它,以便它不会陷入循环引用问题?

此外,我确实希望在大多数代码中启用LazyLoading,只是在序列化部分不启用。


如果您不想使用延迟加载,为什么要将属性标记为虚拟的? - Jason Coyne
我希望在大多数情况下使用延迟加载,但当我要序列化对象时,我希望禁用延迟加载。 - StillLearnin
2个回答

2

这对你来说是个问题吗?还是你只是好奇为什么会发生这种情况?

DBContext会为您跟踪所有引用。当您加载章节时,它知道课程与之相关联,并为您连接它们。

您可以通过断开对象或从不同的DBContext加载章节来停止此操作。

myDbContext.Entry(someLesson).State=Detached;

关于序列化问题,请参考以下问答:如何使用Newtonsoft.Json“真正”序列化循环引用对象? 或者 http://johnnycode.com/2012/04/10/serializing-circular-references-with-json-net-and-entity-framework/。请注意,保留了HTML标签。

这对我来说是个问题,因为当我尝试序列化课程时,课程和课程章节之间的循环引用会创建一个无限循环。我刚刚发现,使用单独的上下文可以解决这个问题。你能告诉我“断开对象连接”是什么意思吗? - StillLearnin
myDbContext.Entry(someLesson).State=Detached;但你也可以修复序列化问题。你正在使用Newtonsoft进行序列化吗? - Jason Coyne
http://johnnycode.com/2012/04/10/serializing-circular-references-with-json-net-and-entity-framework/ - Jason Coyne
这让我重新开始,谢谢!我更新了我的问题以反映评论中的附加信息。如果您可以更新您的答案以显示分离方法和适当的来自johnycod的代码片段...它修复了序列化问题,那将使它更清晰地为后人所用。然后我会接受你的答案并点赞它。 - StillLearnin

1

在我看来,这是EF的一种糟糕行为。

EF工作方式如下(可能您已经注意到):当您禁用惰性加载时,关系未被解析(即使您访问属性也不会加载属性)。 在您的情况下,您可以访问les.LessonSections,您会发现它为空或(在您在Lesson构造函数中初始化它的情况下)为空。

如果您使用相同的上下文访问未使用惰性加载加载的对象或集合(构建查询并将其实例化),EF会自动尝试解决关系,就像在惰性加载期间一样(即使对象没有代理)。 这就是您的行为,在完全不同的查询中,您访问LessonSections并且EF解决了Lesson中的关系。

初看起来这是个好行为,但最终您可能会拥有一个不一致的上下文(某些对象的关系已解决,而其他对象则没有),这可能导致应用程序出错。在我看来,如果EF(禁用LazyLoad时)根本不解决关系,并且如果您需要解决它,则手动解决关系,那么行为会更加一致。但这只是我的意见。

关于你的问题,你可以像另一个回答中建议的那样分离对象,或者在同一工作单元中使用两个不同的上下文(使用相同或不同的连接)。我更倾向于(通常使用)第二种方法,在尽早禁用惰性加载的情况下处理上下文。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接