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