Solution "ObjectContext instance has been deleted and can no longer be used for operations that require a connection" InvalidOperationException

I am trying to populate a GridView using Entity Frameworkm, but every time I get the following error:

"The access method for the LoanProduct property for the COSIS_DAL.MemberLoan object raised the following exception: the ObjectContext instance was deleted and can no longer be used for operations that require a connection."

My code is:

 public List<MemberLoan> GetAllMembersForLoan(string keyword) { using (CosisEntities db = new CosisEntities()) { IQueryable<MemberLoan> query = db.MemberLoans.OrderByDescending(m => m.LoanDate); if (!string.IsNullOrEmpty(keyword)) { keyword = keyword.ToLower(); query = query.Where(m => m.LoanProviderCode.Contains(keyword) || m.MemNo.Contains(keyword) || (!string.IsNullOrEmpty(m.LoanProduct.LoanProductName) && m.LoanProduct.LoanProductName.ToLower().Contains(keyword)) || m.Membership.MemName.Contains(keyword) || m.GeneralMasterInformation.Description.Contains(keyword) ); } return query.ToList(); } } protected void btnSearch_Click(object sender, ImageClickEventArgs e) { string keyword = txtKeyword.Text.ToLower(); LoanController c = new LoanController(); List<COSIS_DAL.MemberLoan> list = new List<COSIS_DAL.MemberLoan>(); list = c.GetAllMembersForLoan(keyword); if (list.Count <= 0) { lblMsg.Text = "No Records Found"; GridView1.DataSourceID = null; GridView1.DataSource = null; GridView1.DataBind(); } else { lblMsg.Text = ""; GridView1.DataSourceID = null; GridView1.DataSource = list; GridView1.DataBind(); } } 

Error mentioning LoanProductName column. Mentioned: I am using C #, ASP.net, SQL-Server 2008 as an internal database.

I am completely new to the Entity Framework. I cannot understand why I am getting this error. Can anybody help me?

+92
c # entity-framework
Aug 23 '13 at 8:34 on
source share
7 answers

By default, the Entity Framework uses lazy loading for navigation properties. To make these properties virtual, EF creates a proxy class for your object and overrides the navigation properties to ensure lazy loading. For example. if you have this object:

 public class MemberLoan { public string LoandProviderCode { get; set; } public virtual Membership Membership { get; set; } } 

The Entity Framework will return the proxy inherited from this object and provide a DbContext instance for this proxy to later allow lazy membership loading:

 public class MemberLoanProxy : MemberLoan { private CosisEntities db; private int membershipId; private Membership membership; public override Membership Membership { get { if (membership == null) membership = db.Memberships.Find(membershipId); return membership; } set { membership = value; } } } 

So, the object has an instance of DbContext, which was used to load the object. It's your problem. You have a using block around using CosisEntities. Which provides a context before returning objects. When some code later tries to use the lazy loaded navigation property, it fails because the context is located at that moment.

To fix this behavior, you can use reliable loading of navigation properties that you will need later:

 IQueryable<MemberLoan> query = db.MemberLoans.Include(m => m.Membership); 

This will download all memberships, and lazy loading will not be used. For more information, see Download related objects on MSDN.

+138
Aug 23 '13 at 8:54
source share

The CosisEntities class is your DbContext . When you create a context in the using block, you define the boundaries of your data-oriented operation.

In your code, you are trying to emit the result of a query from a method and then complete the context inside the method. The operation in which you pass the result, then tries to access the objects to fill the grid view. Somewhere in the process of binding to the grid, a lazy loadable property is accessed, and the Entity Framework tries to search to get the values. It fails because the associated context has already ended.

You have two problems:

  • You work with lazy loading when binding to a grid. This means that you perform many separate operations with SQL Server queries that slow down. You can fix this problem by setting the related properties loaded by default, or by asking the Entity Framework to include them in the results of this query using Include .

  • You finish your context prematurely: a DbContext should be available on the entire unit of work in progress, only deleting it when you finish the work. In the case of ASP.NET, the unit of work is usually an HTTP request.

+26
Aug 23 '13 at 8:56 on
source share

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); // No Exception Thrown 

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); // No Exception Thrown 

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.

+12
25 Oct '17 at 17:01
source share

This is a very late answer, but I solved the problem by disabling lazy loading:

 db.Configuration.LazyLoadingEnabled = false; 
+4
May 23 '18 at 17:33
source share

In my case, I passed all the Users models to the column and it didn’t display correctly, so I just passed Users.Name and fixed it.

 var data = db.ApplicationTranceLogs .Include(q=>q.Users) .Include(q => q.LookupItems) .Select(q => new { Id = q.Id, FormatDate = q.Date.ToString("yyyy/MM/dd"), ***Users = q.Users,*** ProcessType = q.ProcessType, CoreProcessId = q.CoreProcessId, Data = q.Data }) .ToList(); var data = db.ApplicationTranceLogs .Include(q=>q.Users).Include(q => q.LookupItems) .Select(q => new { Id = q.Id, FormatDate = q.Date.ToString("yyyy/MM/dd"), ***Users = q.Users.Name***, ProcessType = q.ProcessType, CoreProcessId = q.CoreProcessId, Data = q.Data }) .ToList(); 
+1
May 17 '17 at 14:44
source share

Most of the other answers point to heavy loading, but I found another solution.

In my case, I had an EF InventoryItem object with a collection of InvActivity child objects.

 class InventoryItem { ... // EF code first declaration of a cross table relationship public virtual List<InvActivity> ItemsActivity { get; set; } public GetLatestActivity() { return ItemActivity?.OrderByDescending(x => x.DateEntered).SingleOrDefault(); } ... } 

And since I pulled out of the collection of child objects instead of the context query (using IQueryable ), the Include() function was not available to implement active loading. So instead, I decided to create a context from which I used GetLatestActivity() and attach() returned object:

 using (DBContext ctx = new DBContext()) { var latestAct = _item.GetLatestActivity(); // attach the Entity object back to a usable database context ctx.InventoryActivity.Attach(latestAct); // your code that would make use of the latestAct lazy loading // ie latestAct.lazyLoadedChild.name = "foo"; } 

This way you do not get stuck looking for downloads.

+1
Jul 13 '17 at 17:04 on
source share

If you are using ASP.NET Core and wondering why you are receiving this message in one of the methods of the asynchronous controller, make sure that you return Task and not void - ASP.NET Core has embedded contexts.

(I am posting this answer since this question is high in the search results for this exception message, and this is a subtle issue - it may be useful for people who use Google for this.)

0
Nov 08 '18 at 11:10
source share



All Articles