EF 6 Lazy Loading Disabled but Child Record Loads

2019-02-17 23:52发布

问题:

I'm using EF6 code first. There are two tables, Lesson and LessonSections. The LessonSections table has a foreign key to Lesson.Id

Here is the Lesson class with none important fields removed:

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; }
}

Here is how I'm initiating my data model:

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

Just after my first call to the database to retrieve the first lesson in the database, the resulting object has no LessonSections

Then I make a second call to retrieve the sections into a separate object. (They must be in a separate objects since I want to serialize them to a JSON string and the serializer halts on the circular reference between Lesson and LessonSections if I use the standard EF LazyLoading.)

Now my original object has two sections loaded from the database even though I never accessed the LessonSections property and even though LazyLoadingEnabled is set to False!

Why do the LessonSections get loaded?

Edit:

I'm using Newtonsoft to serialize my object into a JSON string. Maybe there is a configuration setting in Newtonsoft that I should be setting so it doesn't get caught in the circular reference problem?

Also, I do want LazyLoading enabled for the majority of the code, just not for the serializing part.

回答1:

is this a problem for you, or are you just curious as to why its happening?

The DBContext keeps track of all references for you. When you load the sections, it knows that the lessons have references to them, and wires it up for you.

you could stop this by disconnecting the objects , or by loading the sections from a different dbcontext

myDbContext.Entry(someLesson).State=Detached;

For the serialization issue, see this Q&A How Do You "Really" Serialize Circular Referencing Objects With Newtonsoft.Json?

or

http://johnnycode.com/2012/04/10/serializing-circular-references-with-json-net-and-entity-framework/



回答2:

This is, in my opinion, a bad behaviour of EF.

EF works in this way (like probably you already noted): when you disable lazy loading relationships are not resolved (properties are not loaded even if you access the property). In your case you can access to les.LessonSections and you see that is null or (in your case that you initialize it in Lesson constructor) empty.

If you, with the same context access to an object or to a collection not loaded with lazy load (build a query and materialize it) EF automatically try to solve relationships like during lazy load (also if the object does not have a proxy). This is your behavior, in a totally different query you access to LessonSections and EF solves relationships in Lesson.

At first look is a good behaviour but at the end you can have an inconsistent context (some objects with relationships resolved and some other not) and it can result in a buggy app. IMHO, the behaviour could be more consistent if EF (with LazyLoad disabled) doesn't resolve relationships at all and if you need to solve it you do it by hand. But is just my opinion.

About your question you can detach the object like suggested in another answer or use two different contexts (with the same or a different connection) in the same unit of work. I prefere (usually I use) this second approach disposing the context with Lazy Load disabled as soon as possible.