rss
[ Log On ]

Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle

We will see how we can implement Generic Repository Pattern with Entity Framework and how to benefit from that.
12/22/2011 11:07:00 AM 35 comments 11351 times

DRY: Don’t repeat yourself which is a principle of software development aimed at reducing repetition of information of all kinds, especially useful in multi-tier architectures. That’s what Wikipedia says. In my words, if you are writing same code twice, follow these steps:

  • Step back.
  • Sit.
  • Think about it and dwell on that.

That’s what I have done for repository classes on my DAL projects. I nearly all the time use Entity Framework to reach out my database and I create repositories in order to query and manipulate data inside that database. There are some specific methods which I use for every single repository. As you can assume, those are FindBy, Add, Edit, Delete, Save. Let’s see on code what is my story here.

First approach (worst approach)

At first, long time ago, I have been creating all the single methods for each interface. For example below one is one of my repository interfaces:

I am giving examples here with EF 4.2 but I was following this approach with EF 4 which does not contain DbContext class.

public interface IFooRepository {
        
    IQueryable<Foo> GetAll();
    Foo GetSingle(int fooId);
    IQueryable<Foo> FindBy(Expression<Func<Foo, bool>> predicate);
    void Add(Foo entity);
    void Delete(Foo entity);
    void Edit(Foo entity);
    void Save();
}

This repo is for Foo class I have (imaginary). Let's see the implementation for Bar class.

public interface IBarRepository {
    
    IQueryable<Bar> GetAll();
    Bar GetSingle(int barId);
    IQueryable<Bar> FindBy(Expression<Func<Bar, bool>> predicate);
    void Add(Bar entity);
    void Delete(Bar entity);
    void Edit(Bar entity);
    void Save();
}

Implementation nearly exactly the same here. Here is also an example of implementing one of these interfaces:

public class FooRepository : IFooRepository {

    private readonly FooBarEntities context = new FooBarEntities();

    public IQueryable<Foo> GetAll() {

        IQueryable<Foo> query = context.Foos;
        return query;
    }

    public Foo GetSingle(int fooId) {

        var query = this.GetAll().FirstOrDefault(x => x.FooId == fooId);
        return query;
    }

    public void Add(Foo entity) {

        context.Foos.Add(entity);
    }

    public void Delete(Foo entity) {

        context.Foos.Remove(entity);
    }

    public void Edit(Foo entity) {

        context.Entry<Foo>(entity).State = System.Data.EntityState.Modified;
    }

    public void Save() {

        context.SaveChanges();
    }
}

Also imagine this implementation for BarRepository as well. Indeed, there would be probably more repository classes for your project. After playing like that for a while I decided to do something different which still sucked but better.

A better approach but still sucks

I created a generic interface which saves me a lot of keystrokes. Here how it looks like:

public interface IGenericRepository<T> where T : class {
    
    IQueryable<T> GetAll();
    IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
    void Add(T entity);
    void Delete(T entity);
    void Edit(T entity);
    void Save();
}

And how I implemented in on repository interfaces:

public interface IFooRepository : IGenericRepository<Foo> {
    
    Foo GetSingle(int fooId);
}
public interface IBarRepository : IGenericRepository<Bar> {
    
    Bar GetSingle(int barId);
}

You can see that I only needed to implement GetSingle method here and others come with IGenericRepositoy<T> interface.

Where I implement these repository interfaces to my concrete classes, I still need to go over all the methods and create them individually. The repository class looked like as the same. So it leads me to a final solution which is the best one I can come up with so far.

Best approach

The generic interface I have created is still legitimate and usable here. In fact, I won’t touch the repository interfaces at all. What I did here first is to create an abstract class which implements IGenericReposity<T> interface but also accepts another type parameter defined in a generic declaration which is a type of DbConetxt class. Here is how it looks like:

public abstract class GenericRepository<C, T> : 
    IGenericRepository<T> where T : class where C : DbContext, new() {

    private C _entities = new C();
    public C Context {

        get { return _entities; }
        set { _entities = value; }
    }

    public virtual IQueryable<T> GetAll() {

        IQueryable<T> query = _entities.Set<T>();
        return query;
    }

    public IQueryable<T> FindBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate) {

        IQueryable<T> query = _entities.Set<T>().Where(predicate);
        return query;
    }

    public virtual void Add(T entity) {
        _entities.Set<T>().Add(entity);
    }

    public virtual void Delete(T entity) {
        _entities.Set<T>().Remove(entity);
    }

    public virtual void Edit(T entity) {
        _entities.Entry(entity).State = System.Data.EntityState.Modified;
    }

    public virtual void Save() {
        _entities.SaveChanges();
    }
}

This is so nice because of some factors I like:

  • This implements so basic and ordinary methods
  • If necessary, those methods can be overridden because each method is virtual.
  • As we newed up the DbContext class here and expose it public with a public property, we have flexibility of extend the individual repositories for our needs.
  • As we only implement this abstract class only to our repository classes, it won’t effect unit testing at all. DbContext is not in the picture in terms of unit testing.

So, when we need to implement these changes to our concrete repository classes, we will end up with following result:

public class FooRepository :
    GenericRepository<FooBarEntities, Foo>, IFooRepository {

    public Foo GetSingle(int fooId) {

        var query = GetAll().FirstOrDefault(x => x.FooId == fooId);
        return query;
    }
}
public class BarReposiltory : 
    GenericRepository<FooBarEntities, Bar>, IBarRepository  {

    public Bar GetSingle(int barId) {

        var query = Context.Bars.FirstOrDefault(x => x.BarId == barId);
        return query;
    }
}

Very nice and clean. Inside BarRepository GetSingle method, as you see I use Context property of GenericRepository<C, T> abstract class to access an instance of DbContext.

So, how the things work inside our ASP.NET MVC project? this is another story but no so complicated. I will continue right from here on my next post.

UPDATE:

Here is the next post:

How to Work With Generic Repositories on ASP.NET MVC and Unit Testing Them By Mocking

Permalink Add to del.icio.usDigg!Share on FacebookShare on Google BuzzReddit!Stumble it!

Comments

gravatar
#2262
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Chris Marisic on 12/22/11 16:08:16 Thursday (UTC +02:00)

Aren't GetAll & FindBy redundant?

Wouldn't it be clearer with a single "AsQueryable()" method or similar?


gravatar
#2263
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 12/22/11 16:19:19 Thursday (UTC +02:00)

@ChrisMarisic

Good catch. Actually, it wasn't there on my code but while I was writing the post, I wanted to add there. I don't know why but I like it to be there.

As for your suggestion, yes it can be dropped and even as you suggested, we can have one method which accepts an optional paramater that is type of System.Linq.Expressions.Expression<Func<T, bool>.


gravatar
#2264
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Chris Marisic on 12/22/11 16:42:47 Thursday (UTC +02:00)

Having the single queryable method makes mocking ridiculously easy. Using a similar interface, along with Machine.Specifications & Machine.Fakes.Moq

List<Foo> FooRepository = new List<Foo> { ...... }

The<IRepository<Foo>>()
    .WhenToldTo(x => x.AsQueryable())
    .Return(FooRepository.AsQueryable());

Nothing like being able to mock a database with a list. With a 2nd method you'd end up needing to basically duplicate the above mock but forward the where predicate to FooRepository.AsQueryable().Where(). Kinda lame to mock the same thing twice but only adding a .Where() to it.

 


gravatar
#2275
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by GrahameSD on 12/23/11 19:05:36 Friday (UTC +02:00)

I had come up with a similar pattern in my own work and I followed a similar path to you.  The main differences were that I was using an ObjectContext and I had to return IList<T> rather than IQueryable<T> due to architectural constraints.  But I missed the FindBy with a predicate function - I'll have to start using that.

One thing I'd suggest is to make the Context property in GenericRepository protected so that only the child repositories can get at it otherwise you defeat the object of encapsulating the DbContext.

Anyway, great article.  Keep 'em coming!

 


gravatar
#2276
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 12/23/11 20:02:17 Friday (UTC +02:00)

@GrahameSD

Your suggestion might be good. I must accept that I could be doing something against OOP here which I have no idea what they are. The one of the main reason I did the blog post is to get feedback like yours. 

Thanks!


gravatar
#2277
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by denny on 12/24/11 18:22:22 Saturday (UTC +02:00)

Nice, but how to use a linq join to other tables!


gravatar
#2278
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 12/24/11 18:56:07 Saturday (UTC +02:00)

@denny

GenericRepository<C,T> abstract class exposes a public property named Context for your DbContext class. Use it to create other methods for your needs. Above, on the last code sample, I have an exmaple.


gravatar
#2284
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by andyG on 12/29/11 18:27:04 Thursday (UTC +02:00)

Woudlnt you need to dispose the dbcontext? Im used to using the "Using" statement to make the connections, and im not seeing this being done... it may be my lack of experience in the EF, but i would assume you would need a way to dispose automagically... Does it need to be explicitly called?


gravatar
#2285
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by andyG on 12/29/11 18:32:34 Thursday (UTC +02:00)

I may have answered my own question with more research. I guess it doesnt need to be explicitly called since the context doesnt hold open the connectiion...

http://www.whitneyland.com/2008/06/linq-datacontex.html

http://weblogs.asp.net/scottgu/archive/2007/08/16/linq-to-sql-part-6-retrieving-data-using-stored-procedures.aspx (see comment by scott gu near the bottom)

 

Thanks though... i do love this DRY method a lot...


gravatar
#2286
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 12/29/11 21:53:24 Thursday (UTC +02:00)

@andyG

yep, you are right. DbContext can be disposed. I actually implemented it on my github repo: https://github.com/tugberkugurlu/GenericRepoWebApp

See the commit: https://github.com/tugberkugurlu/GenericRepoWebApp/commit/4a02be1ac1899a476c5f220e042dbbb65546e3cd


gravatar
#2288
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Daniel on 12/30/11 16:08:44 Friday (UTC +02:00)

You would have some issues in the case that certain logic behaviors that are shared across multiple business classes, will use different repositories and, the same way, would use different contexts


gravatar
#2292
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 12/30/11 18:51:40 Friday (UTC +02:00)

@Daniel

Why will different contextes be used? Give an example.

I didn't new up a new context instance inside the repository classes, It just uses the Context property.


gravatar
#2294
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Chris on 01/06/12 23:53:38 Friday (UTC +02:00)

so here's my beef and I can't seem how to navigate this.  Even when you use POCOs you're still coupled to some EF responsibilities.  I want to be able to make model classes any ole way I want and persist them with EF (with some generic implementation if possible) or any other persistence model/device be it NHibernate, XML or simpleDb.  Any suggestions?


gravatar
#2297
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Myles on 01/09/12 19:03:42 Monday (UTC +02:00)

@Chris

IGenericRepository is not specific to the EF. IGenericRepository would be defined in your Model somewhere. The EF project would define an implementation of IGenericRepository in the abstract class GenericRepository as was demonstrated above. If you needed to access any other data sources, you could build out your own implemenation of the IGenericRepository for that type of datasource, whether it be NHiberante, XML, or whatever. If the code you are writing to hit your repositories references the Interfaces and not the Implementations and using Dependency Injection it would be really simple to change from one implementation to another with a simple factory class or StructureMap etc... with very little effort.


gravatar
#2303
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Peluca on 01/15/12 1:42:33 Sunday (UTC +02:00)

@Tugberk

 

Thank you for the nice generic Base Repo class. I have one question.

Why did you not put the GetSingle method to the other generic methods in the base repo class? 

Just like this sample code:

public T GetSingleById(Expression<Func<T, bool>> predicateId)

        {

            var query = GetAll().Where(predicateId).FirstOrDefault();

            return query;

        }


gravatar
#2304
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 01/15/12 12:16:23 Sunday (UTC +02:00)

@Peluca

That is actually right. It could work nicely but most of the cases, it is more convinient to pass the id of the current object to get the single value and I thought that I couldn't know inside the abstract class what the id of the object is, so I didn't do that.

But your sample is great. I will implement that. BTW, you can fork me or open an issue if you want : https://github.com/tugberkugurlu/GenericRepository


gravatar
#2305
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Peluca on 01/15/12 21:26:11 Sunday (UTC +02:00)

@Tugberk

Well the reason why I suggested that because I wanted to avoid using another class which has to implement the IFooRepository or IBarRepository. I think if this repository is really a generic repository then it should be used like this within a ASP.NET MVC controller:

public ActionResult Index(IGenericRepository repo)

{

var customers = repo.GetAll() // and all the other concrete methods from the GenericRepository class

  return View(customers);

I do not want the overhead of a FooRepository or BarRepository.

I would also like to see or vote for it ;-) that you implement the the suggestion from Chris Marisic about the FindBy and GetAll().


gravatar
#2306
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 01/15/12 22:29:47 Sunday (UTC +02:00)

@peluca

I will include that as well but believe me, for a real word app you will definately find yourself implementing those repositories.

On the other hand, if you don't implement concrete repo classes, you will need to mock the DbContext class on unit testing which will be hard to do.

Check my other post on this and you will see what I mean: 

How to Work With Generic Repositories on ASP.NET MVC and Unit Testing Them By Mocking


gravatar
#2307
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Peluca on 01/15/12 23:17:55 Sunday (UTC +02:00)

I do Unit tests on my mvc controller and integration tests for my repository including the business logic inbetween. So I do not need to mock the DbContext as I do not unit test my repository. Hope I got it right and understood you right. Thats an interesting link: http://stackoverflow.com/questions/6766478/unit-testing-dbcontext


gravatar
#2308
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Peluca on 01/16/12 20:39:10 Monday (UTC +02:00)

@Tugberk

 

ah I see you already found it out :P

 

http://stackoverflow.com/questions/8623664/best-way-of-testing-repositories-which-use-dbcontext


gravatar
#2309
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Peluca on 01/16/12 20:46:39 Monday (UTC +02:00)

@Tugberk

 

Still one thing came to my mind. Do you see any reason why not to include the save method

 

 

public virtual void Save()

        {

            _entities.SaveChanges();

        }

 

 

into each Add/Delete/Edit repository method? That way I have not to call the Save explicitly and sometimes I could forget it...


gravatar
#2310
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 01/17/12 12:19:59 Tuesday (UTC +02:00)

@peluca

Yep, I look around a bit on how to unit test with directly consuming DbContext and the only way is to use a database only for testing.

For your second suggestion, it is not a best practice to do that IMO, it is better act on this seperately.


gravatar
#2311
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Ben on 01/18/12 12:08:41 Wednesday (UTC +02:00)

Thanks a lot for this article !

My current implementation was exactly the one you used as First Approach (worst one) ... guess we read the same ASP.NET MVC book ;) I knew it was not the correct approach for my project and I was trying to find a way to refactor it. Your article greatly helped me through this.

I have however changed something in your implementation. What I thought was bad in my implementation (your first approach) was not only the fact that there was a lot of code duplication but also that I was completly trashing the nice UnitOfWork pattern being DbContext.

Indeed I was instanciating one DbContext PER repository, which is not (I think) a good thing. I had to run through a concrete problem to understand that. Everything was ok until a few days ago I had to do a complex linq query requiring doing an union on two DbSets (coming from two distinct repositories). I was thrown an ugly exception letting me know that no union was possible because unions needs to be done in the same DbContext (seems logical). 

I then realized that a single DbContext instance should be shared by all repositories, which is more than logical if you think about it, and correctly exposes the DbContext as a single UnitOfWork.

So what I did is that I changed GenericRepository<C,T> as being only GenericRepository<T>.
I have exposed also exposed the inner DbContext in GenericRepository as a protected field (so that only concrete repository implementations have access to it, I really did not want the domain library user to have access to the context, too dangerous I think and what is the point of the repo in that case ;)).
My DbContext implementation also inherits from an interface called IDataContext which is just empty (solely used for injection purposes). 

The concrete repository implementations are in charge of setting their GenericRepository dbContext upon creation (the dbContext instance is injected via NInject in concrete repository constructors, "InRequestScope").

This way with only a few modifications, the dbContext is only known by the concrete Repositories (for extensions) and to the GenericRepository but not to the outside world, and most of all, the dbContext is shared by all the repositories during the request (UnitOfWork spirit).

To put it in a nutshell, here is what I got :

** IGenericRepository **
public interface IGenericRepository<T> : IDisposable where T : class

** EfGenericRepository **
public abstract class EfGenericRepository<T> : IGenericRepository<T> where T : class
{
/// The concrete implementation ***MUST*** set this context 
protected EfDbContext _efDbContext; 

** EfDbContext **
public class EfDbContext : DbContext, IDataContext

** IDataContext ** 
public interface IDataContext
{        

** ConcreteRepo **
// IDataContext is injected by NInject, InRequestScope
public EfGwConfigRepository(IDataContext context)
{
// Set GenericRepo context
_efDbContext =  context as EfDbContext;

** NInject config **
_ninjectKernel.Bind<IDataContext>().To<EfDbContext>().InRequestScope();

And that's it ;)

Please note that I'm far from being an expert in this field (or I wouldn't have implemented the worst approach in first place ;)), there may be better way to do this, but it worked fine for me and has the advantage of not complexifying the implementation.

Thanks again for your article. 


gravatar
#2312
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 01/18/12 13:55:50 Wednesday (UTC +02:00)

@Ben

Nice comment! One thing I am wondering here is when EfGwConfigRepository comes in to play?

Also, I would love to see the complate implementation, can you put it on github or somewhere else? Looks interesting and different.


gravatar
#2313
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Ben on 01/18/12 19:54:53 Wednesday (UTC +02:00)
The EfGwConfigRepository (one among many other concrete repository) just inherits from GenericRepository and implements IGwConfigRepisitory, just as in your implementation. It comes in play directly in my mvc controllers who require this repo. If the controller need this repo, it takes an IGwConfigRepository as a constructor parameter (code against the interface not the concrete). The concrete repo instanciation is done via ninject constructor injection which binds IGwConfigRepository to EfGwConfigRepository. When Ninject instantiates EfGwConfigRepository it also detects that the constructor requires an IDataContext (chain resolution) which is set to be resolved as EfDbContext InRequestScope (to get a single instance per http request). Then everything is setup and allows me to keep ninject bound to my mvc app and not referenced at all by my domain assembly
gravatar
#2320
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Ben Foster on 01/21/12 12:01:55 Saturday (UTC +02:00)

I prefer to handle my unit of work (e.g. DbContext) outside of my repositories. In your example you are creating a DbContext per repository. Normally I prefer to have a DbContext-per-request that is shared by all repositories.

I do this by abstracting DbContext into an interface and injecting this using a DI tool. Details on my post http://blogs.planetcloud.co.uk/mygreatdiscovery/post/EF-Code-First-Common-Practices.aspx 


gravatar
#2321
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 01/21/12 13:07:30 Saturday (UTC +02:00)

@BenFoster

I'll read the article. Looks interesting and useful. What benefits does this give you by using a DbContext per request? Did you measure the perf? 


gravatar
#2336
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Lisa on 02/09/12 0:16:39 Thursday (UTC +02:00)

Hello Tugberk,

Is it not that every time you create a FooRepository or BarRepository a new instance of type DbContext is created too? If yes, will there not be a problem with having multiple instances of the DbContext going out of sync?

 

Cheers,

Lisa 


gravatar
#2337
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 02/09/12 11:24:30 Thursday (UTC +02:00)

@Lisa

Yes, everytime you create a new repository instance, you will have a new DbContext instance, too. In fact, IMO, you should be working with this way. It prevents collisions.

Here is a quoted sentence on this topic:

The longer you hold onto the context, the more likely you are to get conflicts.

Also, see my next post: 

http://www.tugberkugurlu.com/archive/how-to-work-with-generic-repositories-on-asp-net-mvc-and-unit-testing-them-by-mocking

How I use repositories is safe there.

Also, @Ben has suggested another way above. He has a nice post on that as well.


gravatar
#2338
Do we need a repository?
by Richard Garside on 02/09/12 19:26:12 Thursday (UTC +02:00)

This is a really nice implementation of a repository. But I've been wondering if a repository is the best approach for making testable data access with the Entity Framework. I've heard some conflicting arguements that left me a bit confused.

I blogged about them in this post: Do we need the repository pattern?

I've also blogged about the alternative method I used: Mocking your Entity Framework data context and testing it in .NET MVC

I'd be really interested to see what people think. I like my alternative and it's worked well for me, but I'd like to hear from anyone who knows what the pros and cons of both approaches are.


gravatar
#2339
Do we need a repository?
by Richard Garside on 02/09/12 19:30:01 Thursday (UTC +02:00)

Just seen Ben's comment. Seems like he is using a similar method.


gravatar
#2340
Get Single By ID
by pandincus on 02/10/12 23:50:54 Friday (UTC +02:00)

[Peluca suggests](http://www.tugberkugurlu.com/archive/generic-repository-pattern-entity-framework-asp-net-mvc-and-unit-testing-triangle#2303) a GetSingle(...) method which takes in a predicate:

    public T GetSingleById(Expression<Func<T, bool>> predicateId)
    {
        var query = GetAll().Where(predicateId).FirstOrDefault();
        return query;
    }

I like not having to implement the `GetSingle` method in all of my concrete repositories, but I don't like having to pass a predicate. However, can't we use the native `T DbSet<T> Find(params object[] keyValues)` method to take care of this for us?

> DbSet(Of TEntity).Find Method

> Uses the primary key value to attempt to find an entity tracked by the context. If the entity is not in the context then a query will be executed and evaluated against the data in the data source, and null is returned if the entity is not found in the context or in the data source. Note that the Find also returns entities that have been added to the context but have not yet been saved to the database.

So our implementation can be as simple as:

    public T GetById(int id)
    {
        return _context.Set<T>().Find(id);
    }
   
Granted this means we are constraining our method to accept an integer as the primary key, but that seems like a common enough situation to make this a feasible implementation.


gravatar
#2341
Context-per-Request
by pandincus on 02/11/12 21:23:07 Saturday (UTC +02:00)

Actually I think the proper approach is as Ben suggests to create a context-per-request, not per-repository. What if you need to interact with objects/queries across multiple repositories, as is often the case? Your unit of work object can keep track of the single context, and you can pass this from repository to repository.

In fact, if you dispose of the context too soon and then create a new one, you will also run into conflicts ;-)

Your generic repository can be modified very slightly to accept a context in its constructor:

    private C _context;

    public GenericRepository(C context)
    {
        _context = context;
    }

And then your unit of work, or whatever container class you want, can be in charge of passing the shared context into your various repositories.


gravatar
#2342
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Tugberk on 02/11/12 22:32:30 Saturday (UTC +02:00)

@pandincus

I really think that Ben's suggestion is a really good one and I really would like to put it as an option to this package.

But in my personal opinion, if you need to interact with objects/queries across multiple repositories, there is probably something wrong with your domain model or repository implementation. Some of the project I have done earlier was like that and they all ended up dead because of the wrong implementation of repositories and domain model. Not to mention that it makes it hard to refactor your code.


gravatar
#2343
re: Generic Repository Pattern - Entity Framework, ASP.NET MVC and Unit Testing Triangle
by Matt C on 02/12/12 2:30:05 Sunday (UTC +02:00)

Good post. Definitely agree, per-request is best (actually, per-whatever is needed is best, depending on your implementation, so let the IoC implementation dictate) - the repository doesn't need to know about the persistence details, the unit of work takes care of that, including transactions, etc...
Using a UnitOfWork across repositories minimizes the need to open and close connections to the database, and also allows you to create service methods where the business logic transcends a particular repository. In SharePoint for example, I can then have 1 repository talk to a sharepoint list, another talk to a set of database tables, and if the repository that talks to the sharepoint list fails a check, I can kill the transaction which effectively kills the transaction for the entire request, across repositories, which is nice. The UnitOfWork is not thread-safe, and doesn't need to be, it's per thread (typically). So passing the DbContext into a repository is a necessity in this case, although, the DbContext here is just an implementation of one UnitOfWork class, which doesn't only need to span a DbContext, but could be a broader Persistence abstraction on top of different types of persistences stores (like sql, sharepoint, and media storage for example all in one request).
I have one version of an implementation of a Repository and UoW (although not for Code-First, but it's pretty much the same and wouldn't be hard to convert) over here if you're interested.



Additional allowed tags : [quote]...[/quote], [user]...[/user]
:
:
: will not be displayed ! (but will show your Gravatar)
:
: