7

What is the best way to manage the context of Entity Framework when using MVC application?

I am using a Repository/Service pattern.

Edit

After looking through some of these questions: stackoverflow.com/users/587920/sam-striano, I am more confused then before. Some say use the context per repository, but wht if I want to use multiple repositories in one controller method?

And to follow good separation design, how do you use UnitOfWork in the MVC app with out making it dependent on EF? I want to be able to unit test my controllers, model, services, etc. using a mock context?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Andrew
  • 73
  • 4
  • this was discussed many times. For example I recommend you questions from this user from last week: http://stackoverflow.com/users/587920/sam-striano Then ask for concrete problem you found. – Ladislav Mrnka Mar 05 '11 at 18:12
  • This is a good post that shows code for EF Code First Repository Patter with a Unit of Work. It uses Structuremap as an IoC and has code examples for everything. http://stackoverflow.com/questions/4442828/entity-framework-4-ctp-4-ctp-5-generic-repository-pattern-and-unit-testable – Paul Mar 05 '11 at 22:18

2 Answers2

6

Use a Dependency Injector/Inversion of Control framework like:

  1. Ninject
  2. Autofac
  3. StructureMap
  4. Unity

Using an IoC container, you can tell it how to manage a single data context (most commonly, per request). When you set the data context to per request, the container will auto-magically give any class that needs a data context the same data context per request.

Here is a good article on setting up Ninject.

What your code will most likely end up looking like, assuming you're using a generic repository:

Ninject Module:

public class NinjectRegistrationModule : NinjectModule
{
    public override void Load()
    {
        Bind<MyDataContext>().ToSelf().InRequestScope();
        Bind(typeof(RepositoryImplementation<>)).ToSelf().InRequestScope();

    }
}

Generic Repository:

public RepositoryImplementation<T> : IRepository<T> where T : class
{
    MyDataContext _dataContext;

    public RepositoryImplementation<T>(MyDataContext dataContext)
    {
        _dataContext = dataContext;
    }

    // bunch of methods that utilize _dataContext
}

Service Class:

public class MyServiceClass
{
    IRepository<SomeEntity> _someEntityRepository;

    public MyServiceClass(IRepository<SomeEntity> someEntityRepository)
    {
        _someEntityRepository = someEntityRepository;
    }

    // do stuff with _someEntityRepository = someEntityRepository;
}

Controller:

public class MyController
{
    MyServiceClass _myServiceClass;

    public MyController(MyServiceClass myServiceClass)
    {
        // Ninject will auto-magically give us a myServiceClass
        // which will Ninject will inject a repository into MyServiceClass's constructor
        _myServiceClass = myServiceClass;
    }

    public ActionResult MyAction()
    {
        // use _myServiceClass to do stuff
        return View();
    }
}
Omar
  • 39,496
  • 45
  • 145
  • 213
  • I love DI, but you should still instantiate the ObjectContext from within the repository. For instance, consider the consequences of a Repository that is configured as a singleton by the IoC container and receives an ObjectContext as a constructor argument. – smartcaveman Mar 05 '11 at 20:41
  • Great post, thanks! I have a couple of questions though. 1) In the Ninject Bind examples, I am using EF4, where do you get the context from Bind().ToSelf().InRequestScope();. The MVC app should know nothing of EF, correct? – Andrew Mar 05 '11 at 23:28
  • Have you tried putting the Ninject module in your service layer and just reference it in your ASP.NET MVC project? – Omar Mar 05 '11 at 23:49
  • So the Context should live in the service layer, then you use Ninject to inject it into all objects that need it? Ninject will create it in the MVC app and send it to the repository layer automatically just bu knowing the repository needs it? What about the UnitOfWork? Do you have any examples of this? - Thanks! – Andrew Mar 06 '11 at 04:02
0

If your functionality is straight forward, then you should create a new ObjectContext in each Repository. They are cheap to instantiate.

If this creates a conflict, you can use a Unit of Work pattern as was suggested in the comment.

I would advise that you be extremely cautious when integrating an ObjectContext or DataContext with a DI container. Many do not use the appropriate scope for their life cycle by default.

smartcaveman
  • 41,281
  • 29
  • 127
  • 212
  • Having new context for each repository is something that works only in simple scenarios. You usually found that you want to share context among multiple repositories. This is usually handled by using UnitOfWork pattern. – Ladislav Mrnka Mar 05 '11 at 18:14
  • @smart - Thank you for the link, but how about a sample implementation? – Andrew Mar 05 '11 at 18:28
  • 1
    http://dotnet.dzone.com/news/using-unit-work-pattern-entity?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed:+zones/dotnet+(.NET+Zone) – smartcaveman Mar 05 '11 at 18:34
  • and, http://devtalk.dk/2009/06/09/Entity+Framework+40+Beta+1+POCO+ObjectSet+Repository+And+UnitOfWork.aspx – smartcaveman Mar 05 '11 at 18:35