MVC 3 - The ObjectContext instance has been disposed and can no longer be used for operations that require a connection
Asked Answered
C

1

5

I'm very new to C# and MVC in general and I've been creating my own little blog site as a test project. Although most things are working up to this point, I have had problems selecting multiple columns from LINQ queries. It was only after stumbling on a question on SO that I realised I could use the generated entities classes as strongly-typed models to handle this. I've needed this as I've been creating a database layer (which is also something I've not used before) and trying to pass anonymous types through that layer didn't work. I understand why that was the case, so I'm satisfied that I'm heading in the right direction.

However, this approach seems to have given me another problem. I've tried a simple test to retrieve 2 columns from my Categories table: CategoryID and Name. I initially tried the following:

using (MyEntities db = new MyEntities())
{
    var model = from c in db.Categories
                select new Category { CategoryID = c.CategoryID, Name = c.Name };

    return View(model);
}

This gave me the ObjectContext is disposed error when trying to iterate over the model in the view. After reading this question, I tried moving the return statement outside of the using block and calling AsEnumerable() on the model like so:

IEnumerable<Category> model;

using (MyEntities db = new MyEntities())
{
    model = from c in db.Categories
            select new Category { CategoryID = c.CategoryID, Name = c.Name };
}

return View(model.AsEnumerable());

However, this is still giving me the same ObjectContext is disposed error when I try to iterate over the model in the view. So now I don't understand why I'm getting the error. I've even tried removing the using directive completely but that gives me a different error:

"The entity or complex type 'MyProjectModel.Category' cannot be constructed in a LINQ to Entities query."

If it helps, here's the relevant code for my view:

@model IEnumerable<MyProject.Models.Category>

@foreach (var category in Model)
{
    <p>@category.Name</p>
}

Would someone be kind enough to enlighten me as to what I'm missing?

Thanks.

Consecrate answered 19/6, 2011 at 20:4 Comment(0)
H
12

Be eager in the controller and call .ToList() before disposing in order to schedule the execution of the query immediately before you have left the using block (as after that it is too late, the context is gone):

using (MyEntities db = new MyEntities())
{
    var model = 
        from c in db.Categories
        select new Category 
        { 
            CategoryID = c.CategoryID, 
            Name = c.Name 
        };
    return View(model.ToList()); // <-- .ToList() here
}

Now, while this will solve your particular problem, what developers or dependency injection frameworks usually do is to instantiate the DbContext inside the BeginRequest event, store it inside the HttpContext.Items so that it is available throughout the execution of the entire request and inside the EndRequest method, retrieve it from HttpContext and dispose it.


UPDATE:

Also it is a good practice to use a view model containing only the properties you would like to use in this particular view:

public class CategoryViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
}

and then inside your action:

public ActionResult Index()
{
    using (MyEntities db = new MyEntities())
    {
        var model = 
            from c in db.Categories
            select new CategoryViewModel
            { 
                Id = c.CategoryID, 
                Name = c.Name 
            };
        return View(model.ToList());
    }
}

and in the view:

@model IEnumerable<MyProject.Models.CategoryViewModel>

@foreach (var category in Model)
{
    <p>
        Id: @category.Id 
        Name: @category.Name
    </p>
}
Hoffer answered 19/6, 2011 at 20:6 Comment(10)
.ToList() is (slightly) fasterParasang
Hi Darin, thanks for the response but that gives me the complex type cannot be constructed in a LINQ to Entities query, error. I don't know if it makes a difference but the Category class was auto-generated for me as part of my entities model.Consecrate
@johnh, I am really not familiar with LINQ to Entities but anyway, try like this directly return View(db.Categories.ToList()); inside the using block.Hoffer
@SLaks, yes, that's correct. Thanks for pointing this out. Answer updated.Hoffer
@Darin, trying that directly has worked. However, that now selects all fields in the table and all related data from foreign keys. How can I select just those 2 columns (which is my original goal)? Really appreciate the answer/comments.Consecrate
@johnh, oh, sorry, I have strictly no idea about how Entity Framework works (and I don't want to know by the way :-)). Maybe someone more familiar with this framework will be able to help you. Anyway, that's no longer related to ASP.NET MVC at all but more about the underlying data access technology you are using which happens to be Entity Framework.Hoffer
@Darin Thanks a lot for the help mate. You too, SLaks. Let's see if someone else knows what I'm missing. :)Consecrate
@johnh, can you try the following (no idea if it's gonna work and cannot test it): define a new class containing two properties Id and Name and then write your query like this: return View(db.Categories.Select(x => new SomeModel { Id = x.CategoryID, Name = x.Name }).ToList());. And then inside your view use @model IEnumerable<SomeModel>.Hoffer
@johnh, please see my updated answer with a detailed example.Hoffer
@Darin, ok I tried something similar to that by which I created a new class, TestClass which had 2 properties representing the ID and the Name Category properties. I used it in the same way as the Category class before but this time it works. So I guess that begs the question, why can I not use a class created by the Entity Framework for the same task? Perhaps I should ask that as a separate question. Thank you!Consecrate

© 2022 - 2024 — McMap. All rights reserved.