Managing DbContext EF6 - c#

I'm building a Webforms EF6 database first application and am not sure how best to manage DbContext. I looked at a lot of tutorials and forum posts but I'm still sure. Regarding the much favored 'using per request', I've not found a way to save parent & children in one go. I got it to work with the code below, but where and when would I dispose of the context? Can I use this approach? Would the per request approach by Kamyar shown here be better?
Here's what I've got now:
public static class ContextManager
{
[ThreadStatic]
private static MyContext current;
public static MyContext MyCurrentContext
{
get{
if (current == null)
current = new MyContext();
return current;
}}
}
coupled with
var context = ContextManager.MyCurrentContext;
.....
context.SaveChanges();
Thanks in advance for any help!
A specific example would be 'UserProfile' which contains child objects as properties such as 'DefaultInvoiceAddress' which returns the user's default invoice address from a table with all the user's addresses. In the last web application I worked on, when user edits this address from within the profile (e.g. street change), together with other profile information from other tables, EF would save all edited information from the different tables in one request (ensuring they're attached). Since I wasn't privy to the context management, I don't know how it was done, but we would always assign a common current context for the requests.
I came across this post by Rick Strahl, and this one by Jordan van Gogh - the business object / transaction seem to be an answer, but I don't quite understand how to implement it and couldn't find an example. The 'shared ObjectContext instance per HTTP request' corresponds to Kamyar's answer mentioned above, and all things considered, it sounds a good option. Would I have to explicitly dispose of the context, if so when/where?. Are there any drawbacks?

Bad idea. Static is totally against the best practices. No 2 users ever will use the app at the same time? Ouch. For WebForms.
Per request IS the best choice.

The EF db context object is not, I repeat NOT threadsafe no matter how you manage it. Lots of problems can arise from sharing a db context across threads so the best way is, as mentioned above to use it per request.
If you don't want to jump into the IoC/DI side of things a really simple way to do it is whenever you need the database you just instantiate your context in a using block, like so:
using(var db = new MyContext())
{
// code reading from/writing to database
...
...
}

Using singleton pattern with entity framework database context is a design defect specially if you work with concurrency environment such as web forms because you have to take in your consideration that DbContext is not thread safe object.

Related

ASP.NET MVC with EF and the Dispose Pattern

I'm writing an ASP.NET MVC application with EF. I have some questions regarding whether or not my approach is reasonable. Note: I simplified my basic structure for this question, in realitiy everything is coupled more loosely.
Let's assume a View that allows a user to change properties of a complex domain model. The data originates from the Database (via EF) and has to be written back again in the end.
From my understanding, each request results in a new controller instance being called. Therefore, I'm using the 'Dispose Pattern' described here as Option 2, which ensures a new DbContext for every request:
public class MyController : Controller
{
private MyContext repo = new MyContext();
protected override void Dispose(bool disposing)
{
this.repo.Dispose();
base.Dispose(disposing);
}
//more code...
}
Now there is a public ActionResult Edit(elementId) method on the controller that will fetch an element from the database and displays an editor for it. Once this request is finished, any reference to the Dbcontext is gone, but I still have access to the Entity-Object fetched from the DB as I store it in my session.
Later on the user presses a 'Save' button on the View. The request to the Save-method of my Controller once again creates a new instance of the Controller and therefore a new DbContext. The Entity-object stored in my session is retrieved and its properties are modified according to the user's input. To save the new state to the database, I have to attach it to the new context:
public void Save()
{
this.repo.MyTable.Attach(myEntity);
myEntity.Name = "New Name";
this.repo.SaveChanges();
}
This can only work once the old Controller with the original DbContext of myEntity has been disposed, otherwise 'Attach' would fail (unable to attach Entity to two contexts). I'm concerned whether or not I can rely on the old DbContext being disposed here.
Also: I know that using an IoC framework would be an alternative. How would that apply to my situation, what would be the benefits?
I think you've redacted too much of your code in an effort to "simplify" the question, and as a result, have actually obscured some important issues. However, based on the Save method you've posted, I can pretty well guess your issue. Your repo is most likely creating it's own context, which is a pretty big no-no.
To answer you overall question, the rationale for implementing IDisposable here is the same as anywhere else: any class that owns dependencies that implement IDisposable should also implement IDisposable. Here, your controller instantiates MyContext, so it should therefore dispose of MyContext when its done. Simple as that.
However, if you introduce dependency injection, and inject the context into the controller, then the controller no longer owns the context. Instead, the DI container will own it. Therefore, your controller should not dispose of the context, as it does not own it.
And, you should use dependency injection here. Your context should be injected into your repository and then your repository should be injected into your controller. This ensures that there's is only one context instance, and you won't have issues like you're experiencing now, where EF complains that the entity belongs to a different context.
Finally, I just want to parrot #SteveGreene in saying that there is absolutely no reason to store your entity in the session, and in fact there's many reasons you shouldn't, not the least of which being it will frustrate any efforts to move away from In Proc sessions to a more reliable session store. Once you're using something like StateServer, SQL Server, Redis, etc., anything you put in the session must be serializable, and entities are often quite difficult if not impossible to serialize, since they often have many relationships with other entities and often circular relationships with those entities.

Is it proper form to extend a model object (e.g. Product) and add a Create() method that inserts into the database? (MVC 5 Entity Framework 6)

So I am currently extending the classes that Entity Framework automatically generated for each of the tables in my database. I placed some helpful methods for processing data inside these partial classes that do the extending.
My question, however, is concerning the insertion of rows in the database. Would it be good form to include a method in my extended classes to handle this?
For example, in the Product controller's Create method have something like this:
[HttpPost]
public ActionResult Create(Product p)
{
p.InsertThisProductIntoTheDatabase(); //my custom method for inserting into db
return View();
}
Something about this feels wrong to me, but I can't put my finger on it. It feels like this functionality should instead be placed inside a generic MyHelpers.cs class, or something, and then just do this:
var h = new MyHelpers();
h.InsertThisProductIntoTheDatabase(p);
What do you guys think? I would prefer to do this the "correct" way.
MVC 5, EF 6
edit: the InsertThisProductIntoTheDatabase method might look something like:
public partial class Product()
{
public void InsertThisProductIntoTheDatabase()
{
var context = MyEntities();
this.CreatedDate = DateTime.Now;
this.CreatedByID = SomeUserClass.ID;
//some additional transformation/preparation of the object's data would be done here too. My goal is to bring all of this out of the controller.
context.Products.Add(this);
}
}
One of the problems I see is that the entity framework DBContext is a unit of work. if you create a unit of work on Application_BeginRequest when you pass it into controller constructor it acts as a unit of work for the entire request. maybe it's only updating 1 entity in your scenario, but you could be writing more information to your database. unless you are wrapping everything in a TransactionScope, all these Saves are going to be independent which could leave your database in an inconsistent state. And even if you are wrapping everything with a TransactionScope, I'm pretty sure that transaction is going to be promoted to the DTC because you are making multiple physical connections in a single controller and sql server isn't that smart.
Going the BeginRequest route seems like less work than adding methods to all of your entities to save itself. Another issue here is that an EF entity is supposed to be a not really know anything about it's own persistence. That's what the DbContext is for. So putting a reference back to the DbContext breaks this isolation.
Your second reason, adding audit information to the entity, again adding this to each entity is a lot of work. You could override SaveChanges on the context and do it once for every entity. See this SO answer.
By going down this road I think that you are breaking SOLID design principles because your entities violate SRP. introduce a bunch of cohesion and you are ending up writing more code than you need. So i'd advocate against doing it your way.
Why don't you simply use:
db.Products.Add(p);
db.SaveChanges();
Your code would be much cleaner and it will certainly be easier for you to manage it and get help in the future. Most of samples available in internet use this schema. Extension methods and entities does not look pleasnt.
BTW: Isn't InsertThisProductIntoTheDatabase() method name too long?

How do I maintain referential transparency between related entities without relying on a common data context instance?

Thanks for looking.
Background
In my .NET applications I usually have a Business Logic Layer (BLL) containing my business methods and a Data Access Layer (DAL) which contains my Entitiy classes and any methods for dealing with atomic entities (i.e. CRUD methods for a single entity). This is a pretty typical design pattern.
Here is a pseudocode example of what I mean:
BLL
public static int CreateProduct(ProductModel product){
return DAL.SomeClass.CreateProduct(new DAL.Product{
Name = product.Name,
Price = product.Price
});
}
DAL
public int CreateProduct(Product p){
var db = new MyDataContext();
db.Products.AddObject(p);
db.SaveChanges();
return p.Id;
}
No problems with this simple example.
Ideally, all the business of instantiating a data context and using that data context lives in the DAL. But this becomes a problem if I attempt to deal with slightly more complex objects:
BLL
public static int CreateProduct(ProductModel product){
return DAL.SomeClass.CreateProduct(new DAL.Product{
Name = product.Name,
Price = product.Price,
ProductType = DAL.SomeClass.GetProductTypeById(product.ProductTypeId) //<--PROBLEM
});
}
Now, instead of saving the entity, I get the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker
Ok, so the answer to dealing with that is to pass a common data context to both calls:
BLL
public static int CreateProduct(ProductModel product){
using{var db = new DAL.MyDataContext()){
return DAL.SomeClass.CreateProduct(new DAL.Product{
Name = product.Name,
Price = product.Price,
ProductType = DAL.SomeClass.GetProductTypeById(product.ProductTypeId, db) //<--CONTEXT
}, db); //<--CONTEXT
}
}
Problem
This solves the immediate problem, but now my referential transparency is blown because I have to:
Instantiate the data context in the BLL
Pass the data context to the DAL from the BLL
Create overridden methods in the DAL that accept a data context as a parameter.
This may not be a problem for some but for me, since I write my code in a more functional style, it is a big problem. It's all the same database after all, so why the heck can't I deal with unique entities regardless of their data context instance?
Other Notes
I realize that some may be tempted to simply say to create a common data context for all calls. This won't fly as doing so is bad practice for a multitude of reasons and ultimately causes a connection pool overflow. See this great answer for more details.
Any constructive input is appreciated.
Personally, I track my unit of work and associate a data context to it via static methods. This works great if you aren't talking about operations with long lifetimes, such as my current project, an ASP.NET application, where every request is a (mostly) distinct unit and a request start and end coincide with the unit start/end. I store data context in the request CurrentContext, which, if you aren't familiar with it, is basically a dictionary managed by the system that allocates a request-specific storage accessible by static methods. The work's already done for me there, but you can find lots of examples of implementing your own unit of work pattern. One DbContext per web request... why?
Another equally workable answer for many is injection. Used for this purpose (injecting datacontext), it basically mimics the code you wrote at the end of your question, but shields you from the "non-functional" stuff you dislike.
Yes, you are only accessing one database, but if you look closely, you will see the database is not the constraint here. That is arising from the cache, which is designed to permit multiple, differing, concurrent copies of the data. If you don't wish to permit that, then you have a whole host of other solutions available.

Context duplication on nested call to linq operations

I have refactored some querys on linq in order to have two calls:
public IQueryable<Entity> GetAll()
{
return context.Set<ENTITY>().Project().To<Entity>();
}
That is called from:
public int FindLastID()
{
using(var context = new DBContext())
{
return GetAll().Max(p => p.id);
}
}
The problem is that GetAll should be independently used, and it has no context. If the using context in wirtten on the GetAll method it is disposed and the Max function generates an excetion.
Is any way of calling the GetAll with no exception?
Usually all repository methods assume that a context is created. This is the most convenient way. So your FindLastID method also shouldn't create the context, unless it's a service layer method. One simple example is to use a static variable:
public void AServiceMethod()
{
using (var context = contextProvider.CreateContext())
{
// call some domain operations, which use repositories
// commit
}
}
Where CreateContext will open a DB session and store it in some static variable accessible from all repositories. This is not very elegant, but often is sufficient. To make it better you can use IoC as suggested by Sergey Berezovskiy. Also you may be interested in this article, recommended by Sam Leach in his answer.
Alternatively you could try something like this:
public IQueryable<Entity> GetAll()
{
return GetAll(null);
}
public IQueryable<Entity> GetAll(DBContext context)
{
if (context == null)
{
using (context = new DBContext())
{
return GetAll(context);
}
}
return context.Set<ENTITY>().Project().To<Entity>();
}
But I'd recommend the first approach, as it's simpler and easier to maintain, comprehend.
This question is about Entity Framework Context Management.
See this MSDN article, Working with DbContext
It gives some general guidelines that you might find useful while thinking about refactoring and designing your data access.
When working with long-running context consider the following:
As you
load more objects and their references into memory, the memory
consumption of the context may increase rapidly. This may cause
performance issues.
Remember to dispose of the context when it is no
longer required.
If an exception causes the context to be in an
unrecoverable state, the whole application may terminate.
The chances
of running into concurrency-related issues increase as the gap between
the time when the data is queried and updated grows.
When working with Web applications, use a context instance per request.
When working with Windows Presentation Foundation (WPF) or Windows Forms, use a
context instance per form. This lets you use change-tracking
functionality that context provides.
Using an IoC framework to manage the lifetime of your context is probabably the best approach as Sergey Berezovskiy said.
Also, see this old (but good) article about context lifetime management.

ASP.NET MVC/LINQ - retrieving tables and number of connections

Still extremely new to the whole MVC/LINQ thing. I'm in the processes off building a blog, and I need to build a table for the posts, and within each post build a table for the comments of that post.
To build the tables, I'm doing something like:
postsTable = (new DataContext(connectionString)).GetTable<Post>();
Unfortunately for each comments table, it does the same thing. I see DataContext(connectionString) and assume it's reconnecting every single time. I feel like I should be able to connect once at the start of the fetch and then close the connection when I'm done. Am I doing this wrong?
What your looking for is a pattern called "Session/Context per Request". The most popular and cross ORM, cross WebForms/MVC way of doing this is at the start of a request new up a context, throw in session, and finally at the end pull it down and dispose of it.
From: http://blogs.microsoft.co.il/blogs/gilf/archive/2010/05/18/how-to-manage-objectcontext-per-request-in-asp-net.aspx
public static class ContextHelper<T> where T : ObjectContext, new()
{
#region Consts
private const string ObjectContextKey = "ObjectContext";
#endregion
#region Methods
public static T GetCurrentContext()
{
HttpContext httpContext = HttpContext.Current;
if (httpContext != null)
{
string contextTypeKey = ObjectContextKey + typeof(T).Name;
if (httpContext.Items[contextTypeKey] == null)
{
httpContext.Items.Add(contextTypeKey, new T());
}
return httpContext.Items[contextTypeKey] as T;
}
throw new ApplicationException("There is no Http Context available");
}
#endregion
}
You can also mess around with new()ing up the DataContext in your controller constructor as seen here:
http://www.stephenwalther.com/blog/archive/2008/08/20/asp-net-mvc-tip-34-dispose-of-your-datacontext-or-don-t.aspx
Now this article says you don't have to worry about disposing of your context but I disagree. With modern ORMs you really want to take advantage of the "session" like ways they track and persist changes. Without manually disposing of your context all sorts of bad code or horrible unit of work patterns won't throw exceptions like they should. IMHO the session aspect of an ORM is the most important part. Ignore at your peril.
If your using SQL Server the connection pooling feature negates a lot of the performance impacts of opening and closing a connection. Unless you start doing 100,000 requests a second I wouldn't worry about it.
Go to http://www.asp.net/MVC and check out the tutorials and starter kits there are a whole bunch of good articles that will show you what you are looking for
Since you're doing LINQ to SQL you can...
Define the blogs and comments tables on your database with the appropriate foreign key relationship.
Drag and drop both onto your dbml designer surface. Click the save button; that's when the code is generated.
When you populate your viewmodel (or however you're getting your data back to the result of a controller action) only query the information you need at the time.
For a single view of a blog entry with associated comments ithe LINQ query might look like so...
YourDataContext dataContext = new YourDataContext();
var blogData = (from b in dataContext.Blogs
where b.BlogId == 1
select b).SingleOrDefault();
// you should now have a single blog instance with a property named Comments. Set the
// fetch mode to eager if you plan to always show the comments; leave it lazy to only do
// the lookup if necessary. Execute all of your queries/accesses before you pass
// data to the view

Categories