views:

193

answers:

1

Hi

I have implemented a simple repository pattern for the Entity Framework in a web app.

I have several repositories which all subclass a base which has some common methods in

The base looked like this

public class BaseRepository<TEntity> : IRepository<TEntity>
{
    protected readonly RedirectsEntities Context;

    public BaseRepository()
    {
        Context = new RedirectsEntities();
    }

(RedirectsEntities is the EF datacontext, or whatever it's called)

And I had a RuleRepository and a SiteRepository which subclassed it

However, this caused me problems when looking up a site and using that value to save to a rule

the error was

"ADO.Net Entity Framework An entity object cannot be referenced by multiple instances of IEntityChangeTracker"

Presumably because each repository has a different instance of RedirectsEntities ?

So I found this question : http://stackoverflow.com/questions/694625/ado-net-entity-framework-an-entity-object-cannot-be-referenced-by-multiple-instan

which suggests moving the datacontext to a seperate class, holding it in a a static variable

e.g.

public class DataContext
{
    private static RedirectsEntities _dbEntities;
    public static RedirectsEntities DbEntities
    {
        get
        {
            if (_dbEntities == null)
            {
                _dbEntities = new RedirectsEntities();
            }
            return _dbEntities;
        }
        set { _dbEntities = value; }
    }
}

and then my base repository constructor would look like this :

public BaseRepository()
{
     Context = DataContext.DbEntities;
}

So this appears to have solved my problem, but I am concerned that the scope of RedirectsEntities is now incorrect.

Can anyone comment on this?

+1  A: 

In web applications the most common solution is to scope the context per http request. You initialize the context at the beginning of the request and dispose it at the end. During the request you can save the context in the session state.

If you use a Inversion of Control (IoC) container you can have your container take care of saving the context during the request and supply it to your repositories.

Update

If you are not using a IoC I would create the datacontext at the beginning of the request and put it in the session state. Then I would change the constructor of your base repository to take a instance of your datacontext as a parameter. Then each time you create a repository you get the context from the session and supply it to your repository. And at the end of the request you get the context from the session and dispose it. This way, all your repositories will share the same context over one request.

Mattias Jakobsson
thanks for the answer. I am not using an IoC container. Just doing Poor man's Dependancy Injection (oh the shame!)So in this case would I have the DataContext as a property on the repository? And new up a DataContext before creating an instance of the repository? And then set the datacontext property on the repository?
Christo Fur
See my updated answer.
Mattias Jakobsson
thanks...this is quite a good artice on scoping per request (albeit with Lightspeed rather than EF)http://www.mindscape.co.nz/blog/index.php/2008/05/12/using-the-unit-of-work-per-request-pattern-in-aspnet-mvc/
Christo Fur