3

As with most people I've been coming to grips with certain ins and outs of the Entity Framework. One of those things is the lifetime of the context. I'm using a repositories and have decided that a context will live for the length of the request. So the context would need to be injected from the web tier wherever that repository gets used.

I've written some code which I'm sure could be refactored (in fact, definitely!). So based on the concept above, how would you optimise the following repository helper?

public class RepositoryHelper
{

    public static CountryRepository GetCountryRepository() {
        return new CountryRepository(HttpContext.Current.GetObjectContext());
    }

    public static CurrencyRepository GetCurrencyRepository()
    {
        return new CurrencyRepository(HttpContext.Current.GetObjectContext());
    }

    public static SettingRepository GetSettingRepository()
    {
        return new SettingRepository(HttpContext.Current.GetObjectContext());
    }

}

A repository is pretty simple and would look like

public class CountryRepository
{

    private Context _context = null;
    public CountryRepository(Context context)
    {
        _context = context;
    }

    public Country GetById(int id) 
    {
        // Would return a country
    }

    public IEnumerable<Country> All()
    {
        // Would return a list of countries
    }

}
Maleks
  • 347
  • 3
  • 9

4 Answers4

2

The challenge here is that what you've constructed isn't a repository in the sense of the repository pattern. A objective of the repository pattern is to abstract the implementation of the data access layer from the problem domain. It's done through a repository that behaves like an in-memory collection of domain objects with which you can perform the normal CRUD functions and often a few more specific operations, i.e. GetByID(id).

The repository then hides the actual persistence layer from the application in effect allowing you to change that layer without impacting the application, i.e. you might start by storing data in a flat file and later move to an RDBMS.

You would normally create an interface to describe the methods your repository needs to implement and actually pass the repository instance around using that interface as the type. This is the abstraction, the interface is common across all possible concrete implementations of your repository but your application is oblivious (to an extent) of which is actually being used.

I'd suggest a step back, look again at the repository pattern and see if you need it. Make sure you aren't just implementing it for the sake of it and that you aren't increasing the complexity of your application unnecessarily. Once you've settled on your data access approach then you can look at how you best utilise the EF Context(s) that you have.

Lazarus
  • 41,906
  • 4
  • 43
  • 54
  • Thanks Lazarus. I've ammended the example repo for clarity (in case my example was incomplete). I think the repository pattern is being used correctly for data access and is seperate from the web domain in the solution. Your third paragraph is what I am most interested in - i.e. how can my web layer interact with these repositories without me having to write a dumb helper that injects the context for each repository type. – Maleks Jun 09 '11 at 12:38
  • @Maleks: I use a DI container (Castle Windsor) to instantiate the Context when the repository is instantiated (which is itself instantiated by the DI container when the active Controller requires it). You repositories should each be based around an aggregate root entity that your web app interacts with, it's beyond the scope of this context to go deeper into that. It's fine for the concrete implementation of the repository to be more tightly coupled to the data access layer, it's virtually unavoidable, but the application to repository coupling should be loose. – Lazarus Jun 10 '11 at 10:46
  • I take your point Lazerus. Will be trying to take concrete examples from the Domain Oriented N-Layered .NET 4.0 App Sample (DDD Architecture) sample project @ http://microsoftnlayerapp.codeplex.com/ – Maleks Jun 10 '11 at 14:18
  • @Maleks: Excellent idea to use that as a reference! – Lazarus Jun 10 '11 at 14:46
0

I think you would benefit from using a Repository Provider class and Repository Factories like in the answer to C#/EF and the Repository Pattern: Where to put the ObjectContext in a solution with multiple repositories? .

Community
  • 1
  • 1
smartcaveman
  • 41,281
  • 29
  • 127
  • 212
0

For DI you can use Ninject and use the InRequestScope method when binding objects.

Andrew
  • 5,395
  • 1
  • 27
  • 47
0

Read my answer here about how to make a generic session manager.

Then create a EntityFramework session manager (which stores the objectcontext).

Some half-done pseudo code:

public static class EntityFrameworkSession
{
    [ThreadStatic] private static ObjectContext _current;

    public static AssignToSessionFactory()
    {
         SessionFactory.Created += OnCreateObjectContext;
         SessionFactory.Disposed += OnDisposeContext;
    }

    public static void OnDisposeContext(object source, SessionEventArgs e)
    {
         if (e.Saved)
           _myContext.SaveChanges();
    }
}

And in your repositories use:

EntityFrameworkSession.Current

to access the context.

Community
  • 1
  • 1
jgauffin
  • 99,844
  • 45
  • 235
  • 372