Bottom line
Your code retrieves data (entities) through an entity structure with deferred loading enabled, and after removing DbContext, your code refers to properties (related / interconnected / navigation entities) that were not explicitly requested.
More specific
InvalidOperationException with this message always means the same thing: you request data (entities) from the entity structure after removing the DbContext.
Simple case:
(these classes will be used for all examples in this answer, and it is assumed that all navigation properties were configured correctly and have related tables in the database)
public class Person { public int Id { get; set; } public string name { get; set; } public int? PetId { get; set; } public Pet Pet { get; set; } } public class Pet { public string name { get; set; } } using (var db = new dbContext()) { var person = db.Persons.FirstOrDefaultAsync(p => p.id == 1); } Console.WriteLine(person.Pet.Name);
The final line will InvalidOperationException because dbContext did not turn off lazy loading and the code gains access to the Pet navigation property after the Context has been removed using the using statement.
debugging
How do you find the source of this exception? In addition to examining the exception itself, which will be generated exactly where it occurs, general debugging rules in Visual Studio apply: set strategic breakpoints and check your variables by hovering over their names, opening (Quickly) Watch the window or using various debug panels such as Locals and Autos
If you want to find out where the link is or is not installed, right-click its name and select "Find all links." You can then set a breakpoint at every location that requests data and run your program with a debugger connected. Each time the debugger stops at such a breakpoint, you need to determine whether your navigation property should be populated or if the requested data is needed.
Ways to Avoid
Disable Lazy-Download
public class MyDbContext : DbContext { public MyDbContext() { this.Configuration.LazyLoadingEnabled = false; } }
Pros: instead of an InvalidOperationException exception, the property will be null. Accessing null properties or attempting to change the properties of this property will throw a NullReferenceException .
How to explicitly request an object if necessary:
using (var db = new dbContext()) { var person = db.Persons .Include(p => p.Pet) .FirstOrDefaultAsync(p => p.id == 1); } Console.WriteLine(person.Pet.Name);
In the previous example, the Entity Framework will implement Pet in addition to Person. This can be beneficial because it is the only database call. (However, there can also be huge performance problems depending on the number of returned results and the number of requested navigation properties, in which case there will be no performance degradation, since both instances represent only one record and one connection).
or
using (var db = new dbContext()) { var person = db.Persons.FirstOrDefaultAsync(p => p.id == 1); var pet = db.Pets.FirstOrDefaultAsync(p => p.id == person.PetId); } Console.WriteLine(person.Pet.Name);
In the previous example, the Entity Framework materializes Pet independently of the person by making an additional call to the database. By default, the Entity Framework keeps track of the objects that it has retrieved from the database, and if it finds the navigation properties that match it, it automatically populates those objects. In this case, since the PetId of the Person object corresponds to Pet.Id , the Entity Framework will assign Person.Pet resulting Pet value before the value is assigned to the variable pet.
I always recommend this approach because it makes programmers understand when and how code requests data through the Entity Framework. When the code throws a null reference exception for an object property, you can almost always be sure that you have not requested this data explicitly.