12

I would like to tie the lifetime of a dbContext to the lifetime of a session, to - for example - be able to commit or abandon changes on a group of mutations on the dbcontext over multiple requests.

Are there any other (better?) ways to accomplish this? If no, what would be a suitable mechanism to create and dispose of the contexts? I am thinking about static hashtables with cleanup on session end, but maybe I'm doing it All Wrong. I am also thinking about the idea of only holding on to those contexts that have to do work over multiple requests, and keeping the rest per action. Any advice?

Martijn
  • 11,183
  • 10
  • 46
  • 92
  • 3
    A couple of things, firstly MVC doesnt have a concept of sessions, its a big part of MVC that its stateless, ie no state between requests. Secondly I personally feel that its a really bad idea to keep a DBcontext open that long anyway as it progressivly gets slower the more objects tracked. this means that your user experience will degrade the longer your user is on the site. – Not loved Oct 25 '12 at 11:45
  • Hi, thanks for the feedback. Could you suggest another way to solve this? Also, I do believe sessions still have quite an important role to play. Shopping carts, staying logged in, etc. etc. etc. is all session based - or at least, I think it is. – Martijn Oct 25 '12 at 12:03
  • 5
    If you are using an IOC container, you can set the lifetime of the context to per web request. That way if you use the context in multiple places in the same request you will use the same context instance. – Maess Oct 25 '12 at 13:00
  • 1
    @Martijn normally with MVC we deal with things a bit differently, for example with Auth we use a cookie to maintain state, this gives the illusion of a persistent login. In the case of your DBcontext i would recommend passing the partial model to the view until its completed, or saving that partial to the database. If youre interested in why EF will be slow with lots of tracked items, check out my post here: http://blog.staticvoid.co.nz/2012/05/entityframework-performance-and.html – Not loved Oct 25 '12 at 14:15

5 Answers5

6

You can use IoC(Inversion of Control) containers to manage the lifetime of DBContext such as StructureMap with following steps :

  1. Install nuget package for MVC 4 : http://nuget.org/packages/StructureMap.MVC4

  2. Read quick start : http://docs.structuremap.net/QuickStart.htm

  3. Set scope of your DBContext : http://docs.structuremap.net/Scoping.htm

Also you can use the combination of Repository and Unit Of Work Patterns for commit or abandon changes on a group of mutations on the dbcontext over multiple requests.

Mohsen Alikhani
  • 1,607
  • 3
  • 19
  • 36
  • Can I use IoC in Winform Projects to manage DbContexts life time also? If yes, Is there any good sample? – Masoud Dec 10 '13 at 08:41
4

This question is answered fairly elegantly in the following SO post:

StructureMap CacheBy InstanceScope.HttpSession not working

Essentially, the magic comes from the following code (adapted for your question and the newer syntax for StructureMap):

ObjectFactory.Initialize(factory => {
    factory.For<MyContext>()
           .CacheBy(InstanceScope.HttpSession)
           .Use(new MyContext(_myConnectionString));
});

Then - in your controller, simply create an instance of the object by using:

var db = ObjectFactory.GetInstance<MyContext>();

Because your IoC (Inversion of Control) set-up via StructureMap has configured the instances to be scoped to HttpSession, you should retrieve the same context each time as long as the session is the same.

However - bear in mind that with DbContext objects, in particular, this is usually a very poor idea - as you are mixing a state-tracking object with a stateless environment, and can easily get yourself into a state where a bad transaction or an object which is in an odd state can stop you from doing any further database calls until you refresh your session.

DbContext objects are generally designed to be extremely lightweight and disposable. It's fully ok to let them drop out of scope and die basically as soon as you're done with them.

Community
  • 1
  • 1
Troy Alford
  • 24,997
  • 8
  • 60
  • 77
  • 6
    One of the reasons for using IoC is decrease coupling and increase cohesion, I think that putting "var db = ObjectFactory.GetInstance();" in the controller to be causes violation of this case. – Mohsen Alikhani Nov 06 '12 at 08:59
  • Yes - possibly so. You can also use `StructureMap` by injecting all controllers (preferred) and then having a constructor for the controller such as: `public MyController(MyContext context) { }` - which will also result in a local copy to use with the same settings. However, in order to help the poster implement that, I would have needed to write a whole series of blog articles and code examples, which seemed inappropriate for this forum. Hence the simple answer which is perhaps imperfect - but workable. – Troy Alford Nov 06 '12 at 17:52
2

It's not a good idia to give DbContext live with the session.

  1. When you have more request it will load some part of data to the context from the DB which make context more big , that means memory issues,

  2. And you will not have updated data compared to DbContet per a request in the context because another user (another session) may have updated the data which you already have loaded to the context.

Caching Entity Framework DbContexts per request

And read this for your options ,

Asp.Net MVC and Session

Community
  • 1
  • 1
Jayantha Lal Sirisena
  • 20,611
  • 10
  • 65
  • 90
  • I'm aware of the drawbacks. I'm looking however for proper solutions. Neither duplicating data tables to staging tables and making the database model incredibly more complex - not to mention the problems with conflict resolution in that solution (solution 2 from the linked question) nor storing possibly complex objects in the session rather than the dbcontext seem a very good idea to me. – Martijn Oct 25 '12 at 12:44
1

Typically in this scenario you need keep changes in temporary store(like session or cookie or database). When you need to save result or view new data you get old data and changes and build new object. Changes can be stored as new object or sequence of actions. Be carfule when apply changes, data conflict may be occure. Of cource use Context\Request

mihanik
  • 51
  • 7
0

In theory you can store a context into the Session dictionary that you can access in each controller. However you might have some threading problem, because at time you store it you are in a different thread than when you retrieve it. If context doesnt use threadstatic varaibles this might work (but I am not sure of this), otherwise not. In any case this is bad design ...none in the web do this...why do you want to store context? You can re-create it at a cheap price in ths subsequent http request. If you need to track changes of properties there are other ways more adequate to the web.

Francesco Abbruzzese
  • 4,119
  • 1
  • 15
  • 18
  • Thanks! Could you give me some hints to some of the other more adequate ways? – Martijn Oct 30 '12 at 23:41
  • 1) Simplest way. Serialize a copy of the ViewModel in json and put it in an hidden field. When the page is posted you deserialize the old ViewModel from json and compare it with the one modified by the user. The way you perform the comparison depends on your needs. 2) Rettrive data from the db, those creating a new context, and then use the UpdateModel, or TryUpdateModel MVC method, to update the properties of this model with the data posted by the user. 3) a mix of 1 and 2, that use TryUpdateModel on the old viewmodel serialized in json. – Francesco Abbruzzese Oct 31 '12 at 00:37
  • 4) If you are using knockout.js there are some libraries that do changes tracking and other advanced stuffs such as the Mvc Controls Toolkit updatesManager js class, or Breeze.js. However this path require you study a lot to learn how all this frameworks works. 5) There are some Mvc Controls such ad Mvc Controls Toolkit and Telerik Datagrids that return just the changes to the server, using different formats..That is they say you which object of the list represented in the grid were modified, inserted or deleted. – Francesco Abbruzzese Oct 31 '12 at 00:40