Declaring Entity FrameWork Contexts with using - c#

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!

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.

Error: DbContext has been disposed

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();

LINQ to SQL (DBML) update entity from different data context

I'm trying to update Entity/model using LINQ to SQL (DBML). but I'm not able to do it.
Here is my code snippet.
public void Update(Customer customer)
{
using (MyDataContext db = new MyDataContext())
{
db.Customers.Attach(customer, true);
db.SubmitChanges();
}
}
public Customer GetByID(int ID)
{
using (MyDataContext db = new MyDataContext())
{
return db.Customers.FirstOrDefault(c => c.CustomerID == ID);
}
}
My scenario is: I get the customer object and bind the customer object to form. and after change the form input data. Data is perfectly change but when I call update method. It's not updating it and I have this error:
An entity can only be attached as modified without original state if it declares a version member or does not have an update check policy.
I searched a lots of internet but I'm not able to find any appropriate solution. I also modified my update function like that:
public void Update(Customer customer)
{
using (MyDataContext db = new MyDataContext())
{
var originalCustomer = db.Customers.FirstOrDefault(c => c.CustomerID == customer.CustomerID);
db.Customers.Attach(customer, originalCustomer);
db.SubmitChanges();
}
}
But still getting the same error.
I don't want to get Customer from database and update it properties from parameter customer properties. I want to use the same parameter customer and update it in database.
Please help me.
Thanks!
The problem is that even though you are using the same DbContext class you are using different DbContext objects because you are using two different "using" statements.
It's important that you use the same DbContext object throughout the request (assuming it's an MVC app).
The usual approach would be to instantiate the DbContext in the controller (or using Dependency Injection ) and use the reference everywhere.
The issue is you have two using statements, giving 2 different context
The easier option would be to inject it into the controller and use it when needed
public void Update(Customer customer)
{
using (MyDataContext db = new MyDataContext())
{
var originalCustomer = db.Customers.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
// change the originalCustomer's properties with customer's properties.
db.SubmitChanges();
}
}

Cannot return type IQueryable or IEnumerable

Since I cannot return either of these types from a Linq to Entities query, I am sticking with returning a List.
On return from the DB call (which is in a separate WCF service or DLL), the code in the Controller fails because the dbcontext connection is closed.
Note the code in the following. For both IEnumerable and IQueryable, the data does not come back because of the above description.
Method in MVC Controller
// Controller
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList().AsEnumerable();
// Error coming back because dbcontext connection was closed.
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
Method in WCF service or DLL
// WCF Service or DLL
public IEnumerable<ProjectDescription> GetProjectDropDownList()
{
try
{
//IQueryable<ProjectDescription> project = null;
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
return project;
}
}
catch (Exception ex)
{
throw ex;
}
}
I even tried the following establishing a DbContext instance before the DB call which still didn't work actually trying to pass down the DbContext to the DB method.
Controller:
DbContext = new YeagerTechEntities();
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList(DbContext).AsEnumerable();
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
DbContext.Dispose();
DB method:
public IEnumerable<ProjectDescription> GetProjectDropDownList(YeagerTechEntities DbContext)
{
try
{
//IQueryable<ProjectDescription> project = null;
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
return project;
}
catch (Exception ex)
{
throw ex;
}
}
The only thing that worked besides using List was to actually place the DB method inside the Controller, which obviously is not good practice whatsoever.
Here is the List convention that works fine:
Controller:
IEnumerable<ProjectDescription> projectDdl = db.GetProjectDropDownList();
ViewBag.ProjectsCust = new SelectList(projectDdl, "ProjectId", "Name");
DB method:
public List<ProjectDescription> GetProjectDropDownList()
{
try
{
using (YeagerTechEntities DbContext = new YeagerTechEntities())
{
DbContext.Configuration.ProxyCreationEnabled = false;
DbContext.Database.Connection.Open();
IEnumerable<ProjectDescription> project = DbContext.Projects.Select(s =>
new ProjectDescription()
{
ProjectID = s.ProjectID,
Description = s.Description
}
);
List<ProjectDescription> myProjects = new List<ProjectDescription>();
myProjects = project.ToList();
return myProjects;
}
}
catch (Exception ex)
{
throw ex;
}
}
If anyone can explain to me what the correct model should be when using IQueryable or IEnumerable, that would be fine. However, after reading this link, it definitely seems like List is the way to go:
IEnumerable vs IQueryable for Business Logic or DAL return Types
The reason why your code failed when using IEnumerable/IQueryable is because the EF query is deferred; that is to say it doesn't actually get executed against the database until you start to enumerate (foreach, etc) or "materialise" (ToList(), etc) the results.
Therefore because you create an effectively temp DbContext with your using{}, the IEnumerable that you pass out of the function is a landmine - the underlying DbContext ceases to exist after the using block, and any attempt to enumerate or materialise the collection will fail.
Even when you created the DBContext without a using block, you then went ahead and Dispose'd of it before you executed the query - hence getting the same error.
This is one of the main reasons for not returning IQueryable from a DAL/Repository - because the recipient cannot know if the underlying context that the query relies on has been closed before they try to consume the results. IEnumerable is much better (List<T> implements IEnumerable<T> of course) and IMHO List is even better because it forces you to return a fully materialised collection and makes it clear to the caller that the result is not connected to the database any more.
So the working version that you have is probably fine - create your context, execute the query and then immediately materialise it which executes the actual SQL and then disconnects the result set from the database. So that pattern will work fine for you.
However I would recommend looking at having things like DbContext injected for you using an IoC container such as Ninject as it frees you from having to worry about the lifecycle of your DbContexts.
Hope that helps.
As you already knows, your DbContext enables you to query your database and so it has to be alive when SQL requests are sent to your SGBD.
The key point here is to know exactly how IQueryable works :
The IQueryable interface inherits the IEnumerable interface so that
if it represents a query, the results of that query can be enumerated.
Enumeration causes the expression tree associated with an IQueryable
object to be executed. The definition of "executing an expression
tree" is specific to a query provider. For example, it may involve
translating the expression tree to an appropriate query language for
the underlying data source.
Which means that as long as your Linq query has not been enumerated (with .ToList() or foreach), no query is sent to the database. The execution is deferred!
In your first attempt, you're :
Calling the GetProjectDropDownList method
Returning an IEnumerable (which is a Ling query) without "enumerating" it
Disposing the DbContext
Enumerating your Linq query through new SelectList when your view is generated but... Your DbContext has already been disposed at that time.
The same applies for your second attempt, the DbContext is disposed a little bit later but also already disposed when the view is generated.
In your last attempt, everything works fine because your DbContextis still alive when you're enumerating your Linq query (with project.ToList();)
In my opinion, isolating your DbContext calls and instances into a Data Access Layer and returning Lists or simple disconnected objects is not a bad practice at all.

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.

Categories