Error: DbContext has been disposed - c#

public JsonResult JTask(int id)
{
using (TestDb db = new TestDb())
{
var a = db.ToDos.Where(todo => todo.UserId == id);
return Json(a, JsonRequestBehavior.AllowGet);
}
}
I have a problem with returning JsonResult
When I run this code code I get the error
"The operation cannot be completed because the DbContext has been
disposed."
I tried adding .ToList() at the end of the line 3, as was suggested, but then I got the error
"A circular reference was detected while serializing an object of type
System.Data.Entity.DynamicProxies."

It's not very obvious, but the built-in Json method only does the serialization after the JTask method has finished executing. By that time, of course, the context has been disposed, resulting in the original error you are describing.
If you have an ICollection<TodoItem> property inside your Todo class, each of those will have a ToDo property which is a reference back to the parent. And each of those ToDo properties will also have ICollection<TodoItem> children, which has a reference back to the parent again, and so on and so forth. This can potentially loop for infinity, and when the serializer tries to serialize the object, it gives up with a circular reference error.
One way to solve both of these problems at the same time is by using viewmodels. A viewmodel is an intermediate class that holds only a subset of the properties that a model class has. The typical flow is for the model class to get converted to a viewmodel first, then it would be the viewmodel that gets serialized as json:
var viewModels = new List<TodoViewModel>();
using (TestDb db = new TestDb())
{
var todoModels = db.ToDos.Where(todo => todo.UserId == id).ToList();
foreach (var model in todoModels)
{
var todoViewModel = new TodoViewModel
{
// Populate viewmodel properties here
Text = model.Text
};
viewModels.Add(todoViewModel);
}
}
return Json(viewModels, JsonRequestBehavior.AllowGet);
I wrote a blog post about the advantages of using viewmodels. You can check it out here if you're interested: Why Use ViewModels

Because Linq is Lazy by the time the JSON tries to get the data out of a (and only then actually goes to db) the db has already been disposed - when leaving the scope of the using
public JsonResult JTask(int id)
{
using (TestDb db = new TestDb())
{
var a = db.ToDos.Where(todo => todo.UserId == id).ToList();
return Json(a, JsonRequestBehavior.AllowGet);
}
}

var a = db.ToDos.Where(todo => todo.UserId == id).ToList();

Related

The operation cannot be completed because the DbContext has been disposed in Web API

My api call is throwing exception "The operation cannot be completed because the DbContext has been disposed". please guide how to resolve it..
Function which is defined in seprate class named as Common Class
public IQueryable productquery()
{
try
{
using (ERPEntities db = new ERPEntities())
{
db.Configuration.ProxyCreationEnabled = false;
var query = db.Products.OrderBy(x => x.ID).AsQueryable();
var list = query.Skip(10).Take(50).AsQueryable();
return list;
}
}
catch (Exception ex)
{
throw;
};
}
Function Call from common function to api Controller
[HttpPost]
public IHttpActionResult GetProducts()
{
try
{
var result = _commonFunctions.productquery();
var resultf = result.Include(x => x.Catagory).ToList();
return Ok(resultf);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
You are trying to include an entity after your DbContext has been disposed.
var resultf = result.Include(x => x.Catagory).ToList();
But you are calling DbContext with using inside productquery() method. If you want to continue to do so, you should finish all db actions inside the using part.
var query = db.Products.Include(x => x.Catagory).OrderBy(x => x.ID).AsQueryable();
The problem is that you create your context:
ERPEntities db = new ERPEntities()
but wrapping it up in a using statement, it would dispose it after the return statement:
return list;
(Undoubtedly you need the disposal of the DB context class, but you have to use the DB context class prior to its disposal. Afterwards, apparently you can't use it.)
For that reason in GetProducts fails, when you materialize the query.
One solution it would be to call ToList before AsQueryable.
var list = query.Skip(10).Take(50).ToList().AsQueryable();
Essentially this would would materialize your query, the data would be fetched from the database, when you call ToList and later on you wouldn't need the context. However, you would have a new problem, Include(x => x.Catagory). This should placed, where you build the query:
var query = db.Products
.Include(x => x.Catagory)
.OrderBy(x => x.ID)
.AsQueryable();
Doing so, I would say that you don't need any more the call to AsQueryable you can removed it from both the signature of your method and the the places you call it.
The most correct answer is to use dependency injection to pass around one instance of your DBContext per http request.
However, the problem is actually just that you are disposing you DBContext before you're done with it. You can move your DBContext to a class-level variable and instantiate it in the CommonFunctions class' constructor. Then you can destroy it on Dispose. This will make it possible for you to do what you want. You will also have to create a function called SaveChanges() which calls .SaveChanges() on the context when you're done doing whatever it is you're doing that needs saving. This is a very quick explanation of something called the Unit of Work pattern.

Controller method not updating(same result every time)

I have following method in my mvc controller:
[HttpGet]
public ActionResult UserProfile(String username)
{
var user = db.Users.Find(username);
return View(user);
}
This function returns View with user profile. But result of this is the same, regardless of changes in database.
When I debug it seems like db is not changing at all, while in other controllers everything works just fine.
EDIT:
Place when I make changes
public ActionResult ExecuteRetreive(String username, String ISBN)
{
if (IsValid(username))
{
var resBook = db.Books.Find(ISBN);
var resUser = db.Users.Find(username);
var resRentedBooks = (from rb in db.RentedBooks
join b in db.Books on rb.ISBN equals b.ISBN
where b.ISBN == ISBN
where rb.Login == username
where rb.Returned == null
select rb).FirstOrDefault();
if (resRentedBooks == null)
{
return RedirectToAction("Fail", "FailSuccess",
new { error = "" });
}
resRentedBooks.Returned = DateTime.Now;
resBook.IsRented = false;
resUser.RentedBooks--;
db.SaveChanges();
return RedirectToAction("Success", "FailSuccess");
}
else
{
return RedirectToAction("Fail", "FailSuccess",
new { error = "Niepoprawna nazwa użytkownika" });
}
}
Im new to this so dont laugh at my code :P When I display resUser.RentedBooks--; it is the same every time.
As a follow up to what #JeroenVannevel said in the comments, another problem that you might be having because you're using a static context (and one that I've had to deal with in the past) is that once a specific DbContext has loaded an entity (or a set of entities, in my case) it won't tend to refresh just because some outside changes were made in the database. It loads those entities into Local and just refers to those automatically if you query for it.
The solution, then, is to always put your DbContext calls wrapped up in a using block, since DbContext implements IDisposable.
One word of caution with this approach, since you're using MVC: If you are using lazy loading, and you know that your View will need some information from a child object (or to list the names of a collection of child objects), you will absolutely need to hydrate those child entities before you get out of the using block, or you will find yourself getting exceptions saying that your context has been disposed.

Declaring Entity FrameWork Contexts with using

Which is the Best Practise in Declaring Entity FrameWork Contexts
function()
{
DBContext context = new DBContext();
//Entity code
return ;
}
or
function()
{
using(DBContext context = new DBContext())
{
//Entity code
}
}
Do we need to use using in EntityFrameWork ? If yes my 2nd question
In DataAccess Layer am executing EF and storing the result in IEnumerable inside using
MY DL
function()
{
IEnumerable something = null;
using(DBContext context = new DBContext())
{
IEnumerable something = ....
}
return something;
}
In Controller
function()
{
List some = something.ToList();
}
And in my controller am getting this as a list as i need to do some Find operation am getting
"The operation cannot be completed because the DbContext has been disposed Entity Framework"
Yes i can return a list from DL and it works fine
How do i handle this if i use using with IEnumerable?
You can avoid the lazy-loading EF behaviour by calling .ToList() on the IEnumerable before the context is disposed (i.e. within your using block)
Yes, a using is the best practice because it cleans up your context. The Using statement is a shortcut for:
try {
// Execute your code inside the using statement
}
finally {
// Cleanup the context no matter what by calling .Dispose()
}
Keep in mind, your context likely returns IEnumerables and since EF supports lazy loading these objects won't be populated until you fetch them to a concrete collection (ie. yourResult.ToList()).
A common negative outcome occurs in this scenario:
public IEnumerable<Employee> GetEmployeesInAccounting()
{
using(var myContext = new MyDbContext())
{
return myContext.Employees.Where(emp => emp.Department == 'Accounting');
}
}
// Code that fails, Assuming Manager is a lazy loaded entity, this results in an exception but it compiles no problem
var acctEmps = GetEmployeesInAccounting();
var something = acctEmps.First().Department.Manager.Department;
You can avoid this by using the .Include(emp => emp.Manager) (linq extension method) and binding your result using .ToList();
Your request will be executed toward the datasource as soon as you'll call .ToList() method.
That's why you cannot perform .ToList() in your Controller as your context as been disposed at the end of the using block.
In your DL method, just do something like:
IEnumerable<Something> function()
{
using(DBContext context = new DBContext())
{
return something.ToList();
}
}
and in your Controller you'll get an IEnumerable of Something:
var mySomethingIEnumerable = DL.Function();
Hope that helps!

Why doesn't entity framework concretize my entity's one to many relationship?

I am using a code-first approach with Entity Framework, and a repository pattern to get entities back from my database. In my data model, each OverallEvent has many EventInConcept children. I want my GetEvents method to return an IList of OverallEvents, and I want the children of the aforementioned relationship to be concretized such that they can be accessed outside my DbContext (which AssessmentSystemContext is). This is the code I currently have:
public IList<OverallEvent> GetEvents() {
using (var context = new AssessmentSystemContext()) {
return context.OverallEvents
.Select(evnt => new {
OverallEvent = evnt,
// evnt.EventsInConcept is a public virtual ICollection<EventInConcept>
ConcreteEventsInConcept = evnt.EventsInConcept
})
.AsEnumerable()
.Select(evntData => {
evntData.OverallEvent.EventsInConcept = evntData.ConcreteEventsInConcept.ToList();
// foreach (var eic in evntData.OverallEvent.EventsInConcept) {
// eic.Name = eic.Name;
// }
return evntData.OverallEvent;
})
.ToList();
}
}
It gives me back a list of OverallEvent entities, which is fine, but the trouble is that if I try to access the child relationship EventsInConcept, I get an error. For example:
EventRepository repoEvent = new EventRepository();
var gotEvents = repoEvent.GetEvents();
var firstEventInConcept = gotEvents[0].EventsInConcept.FirstOrDefault();
... gives me the error "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
I understood from the answer to an earlier question that if I projected EventsInConcept into a wrapper object, then explicitly set it in a later .Select call (ie. evntData.OverallEvent.EventsInConcept = evntData.ConcreteEventsInConcept.ToList();), it would concretize this one:many relationship and I would be able to access EventsInConcept outside of the DbContext, but it isn't working here. Note that if I uncomment the foreach loop, it starts working, so to get it to work I have to explicitly set a property on every single entry of EventsInConcept. I don't really want to have to do this (I'm picking an arbitrary property, .Name, which feels wrong anyway). Is there a better way?
Disable lazy loading for this query. It is of no use in that situation and when you dispose the context after the entities have been retrieved:
public IList<OverallEvent> GetEvents() {
using (var context = new AssessmentSystemContext()) {
context.Configuration.LazyLoadingEnabled = false;
return ...
}
}
It might be possible that EF doesn't recognize that the collection has been loaded when you use a projection (instead of eager or explicit loading) and triggers lazy loading as soon as you access the collection.

Cannot access a disposed object

i'm facing a issue while testing the DAL Library which uses LINQ to SQL
Method that is being Tested as below (a simple one):
public List<tblAccount> GetAccountsByCustomer(tblCustomer customer)
{
using (OnlineBankingDataClassesDataContext dbcntx = new OnlineBankingDataClassesDataContext())
{
var accounts = dbcntx.tblAccounts.Where(p => p.tblCustomer.ID.CompareTo(customer.ID)==0);
return accounts.ToList<tblAccount>();
}
}
Test code is as below:
static tblCustomer GetTopOneCustomer()
{
OnlineBankingDataClassesDataContext dbcntx = new OnlineBankingDataClassesDataContext();
var customers = dbcntx.tblCustomers.Take(1);
return customers.Single<tblCustomer>();
}
public static void Should_List_All_Account_By_Customer()
{
tblCustomer customer = GetTopOneCustomer();
DataController dc = new DataController();
List<tblAccount> accounts=dc.GetAccountsByCustomer(customer);
foreach (tblAccount account in accounts)
{
string accountdetails=string.Format("Account ID:{0} \n Account Type:{1} \n Balance:{2} \n BranchName:{3} \n AccountNumber:{4}",
account.ID.ToString(), account.tblAccountType.Name,
account.Balance.ToString(),
account.tblBranch.Name, account.Number);
Console.WriteLine(accountdetails);
}
}
I'm getting an error "Cannot access a disposed object." when accessing associated object like in this case, I'm using account.tblAccountType.Name. I know it has something to do with DataContext. How shall I get this code working.
dbcntx is a disposable object. The Garbage Collector can come along at any time after GetTopOneCustomer() has been called and dispose of it. Which is what looks like is happening.
Try changing GetTopOneCustomer() to:
static tblCustomer GetTopOneCustomer(OnlineBankingDataClassesDataContext dataContext)
{
//Stuff
}
Then inside Should_List_All_Account_By_Customer() change it like so:
using (OnlineBankingDataClassesDataContext dataContext = new OnlineBankingDataClassesDataContext())
{
tblCustomer customer = GetTopOneCustomer(dataContext);
//More Stuff
}
This way you control the lifetime of the dataContext.
Since the the DataContext is in a using statement, using (OnlineBankingDataClassesDataContext dbcntx = new OnlineBankingDataClassesDataContext())
Disposed will be called on it as soon as the context goes out of scope. This results in all entities beeing detached and all actions on the entity that requires a DataContext will fail.
This is what happens when account.Balance.ToString() is called.
One way to solve this is by creating a new context and use context.Attach(entity).

Categories