6

Interface

public interface IDinnerRepository 
{
    IQueryable<Dinner> FindAllDinners();
    IQueryable<Dinner> FindDinnersByText(string q);

    Dinner GetDinner(int id);

    void Add(Dinner dinner);
    void Delete(Dinner dinner);

    void Save();
}

Class that is inherited from above interface

public class DinnerRepository : NerdDinner.Models.IDinnerRepository
{
    NerdDinnerEntities db = new NerdDinnerEntities();

    Public IQueryable<Dinner> FindDinnersByText(string q)
    {
         return db.Dinners.Where(d => d.Title.Contains(q)
             || d.Description.Contains(q)
             || d.HostedBy.Contains(q));
    }

    public IQueryable<Dinner> FindAllDinners()
    {
         return db.Dinners;
    }

    public Dinner GetDinner(int id)
    {
        return db.Dinners.SingleOrDefault(d => d.DinnerID == id);
    }

    public void Add(Dinner dinner)
    {
        db.Dinners.AddObject(dinner);
    }

    public void Delete(Dinner dinner)
    {
        foreach (RSVP rsvp in dinner.RSVPs.ToList())
            db.RSVPs.DeleteObject(rsvp);

        db.Dinners.DeleteObject(dinner);
   }

   public void Save()
   {
        db.SaveChanges();
   }
}

Usage in a program

public class DinnerOperation
{
    DinnerRepository dr = new DinnerRepository();

    // insert
    public void InsertDinner()
    {
        Dinner dinner = dr.GetDinner(5);
        dr.Dinner.Add(dinner);
        dr.Save();
    }

    // delete
    public void DeleteDinner()
    {
        Dinner dinner = dr.GetDinner(5);
        dr.Dinner.Delete(dinner);
        dr.Save();
    }
}

And without using repository design pattern...

public class DinnerOperation
{
    DinnerEntities entity = new DinnerEntities();

    // insert
    public void InsertDinner()
    {
        Dinner dinner = entity.Dinners.Find(5);
        entity.Dinner.Add(dinner);
        entity.SaveChanges();
    }

    // delete
    public void DeleteDinner()
    {
        Dinner dinner = entity.Dinners.Find(5);
        entity.Dinner.Remove(dinner);
        entity.SaveChanges();
    }
}

Question

I cant understand, in here, Why did we use design pattern? When using the Repository design pattern with Entity Framework in this way does not mean anything.

How can I use design pattern with entitiy framework? When does it make sense to use design pattern with entity framework?

AliRıza Adıyahşi
  • 15,658
  • 24
  • 115
  • 197

3 Answers3

7

You almost got it. First, refactor your dinner operation class so that the repository implementation could be injected into it.

public class DinnerOperation
{
  private IDinnerRepository dr;
  public DinnerOperation( IDinnerRespository repository ) {
     this.dr = repository;
  }

  // insert
  public void InsertDinner()
  {
      Dinner dinner = dr.GetDinner(5);
      dr.Dinner.Add(dinner);
      dr.Save();
  }

  // delete
  public void DeleteDinner()
  {
      Dinner dinner = dr.GetDinner(5);
      dr.Dinner.Delete(dinner);
      dr.Save();
  }
}

Then implement different repositories:

public class EntityFrameworkDinnerRepository : IDinnerRepository
public class NHibernateDinnerRepository : IDinnerRepository
public class Linq2SqlDinnerRepository : IDinnerRepository
public class MockDinnerRepository : IDinnerRepository
....

and then use any repository you want:

var repository = new ....Repository();
var operation = new DinnerOperation( repository );

operation.GetDinner(5);

Repositories are used to abstract your concrete data providers and thus making your architecture more felible.

Want to switch to nHibernate?

Painful, if you have EntityFramework everywhere. Easy, if you use repositories, you just inject another repository and your business logic doesn't have to change.

Want to unit test your business logic?

Painful, if you are stick to a concrete data provider. Easy, if you have repositories, you just inject an inmemory repository which doesn't even use the database.

Got it now?

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • Great Thanks. There are a lot of thing to learn :) . Is there any tutorials, articles, etc... about this topic. I almost got it. What do you recommend to get a better understanding? – AliRıza Adıyahşi Jan 29 '13 at 09:29
  • I don't remember any concise yet complete source. Just Google on "Repository pattern explained", read few more tutorials and study the Dependency Injection pattern which plays well together with the Repository pattern. – Wiktor Zychla Jan 29 '13 at 09:40
  • Switching from EF to NH or an in-memory provider or whatever is not "easy" with a repository that exposes `IQueryable`. – Slauma Jan 31 '13 at 21:06
  • @Slauma: it is surprisingly easy since the class library contains the AsQueryable extension method on IEnumerables. http://msdn.microsoft.com/pl-pl/library/bb353734.aspx Also NH supports linq. I have my repositories implemented for linq2sql, nhibernate, ef, xpo and in-memory and both implement the same interfaces. – Wiktor Zychla Jan 31 '13 at 21:33
  • Yes, NH supports LINQ, but not the same LINQ as EF (LINQ-to-Entities) and LINQ-to-Entities is not LINQ-to-Objects nor LINQ-to-SQL. You can have the same LINQ code, all compiling, but one can work, the other doesn't or it behaves differently. It's provider dependent and you cannot test with a code that use provider 1 if the code that uses provider 2 is working. It's better explained here what I mean: http://stackoverflow.com/a/6904479/270591 (including the links at the end of the answer). – Slauma Jan 31 '13 at 21:58
  • @Slauma: I am aware of these possible issues. The discussion where one should implement repositories to return iqueryables surely is beyond this. – Wiktor Zychla Jan 31 '13 at 22:20
7

I refuse to use the repository pattern when I am using an ORM. I think it has very little if any benefit in that case. (Yes, I expect to get down voted about 2,000 times by zealots).

With EF, I create an interface for my Context

public interface IDinnerContext : IDisposable
{
    IDbSet<Dinner> Dinners;

    int SaveChanges();
}

I then stick this interface on my EF DatabaseContext implementations, and viola! I can use EF everywhere, unit test my db access with MOCK implementations, use injection if I wish, and not end up with 6 million GetByXXX methods. IQeryable handles that, and I get delayed execution. I don't really need Insert/Delete methods because IDBSet already has Add/Remove. I have cleaner/easier to read code with fewer abstractions.

If I DO have a case where the same query is used in many different places, and I really do want that to be common, then I can add some mechanism to support that. However, 95% of the time, queries are specific to the component responsible for business logic X (anything outside the simple GetBy statements). So I don't see that as an issue.

Don't get me wrong, I used the repository pattern religiously until ORMs became pretty decent. Once ORMs reached a certain level of sophistication, I felt the the repository pattern may no longer be required and began doing projects without it.... and have NEVER looked back. I think that everyone else will eventually follow in this direction, or something quite similar, but it will take a while for old habits to die. (I know some devs that still insist on using lock(this) because its still in some of the MS samples).

Keith
  • 1,119
  • 2
  • 12
  • 23
  • +1. a different perspective. I m a bit confused, After your answer. I think, experience is required, When deciding which one to use. This gave me the morale to continue coding. Greate Thanks... – AliRıza Adıyahşi Jan 31 '13 at 22:02
  • Hmm, I guess I kind of made assumptions in there about what people understood/know. There are 2 main reasons people are adamant about using the repository pattern. 1) unit testing, 2) query re-use. Unit testing is now very easy to do in EF with an IDbContext. Query re-use can be handled as well, though I believe that with component driven development there is very little overlap in actual query use between components, so you only need to manage it at a component level, which is easy enough to do...but I still prefer to leverage the flexibility of EF/IQueryable instead. – Keith Mar 05 '13 at 16:31
2

It's the Repository pattern, which in itself would be superflous with Entity Framework because the DbContext serves as a Repository and Unit of Work at the same time, but it's not mockable - there's no IDbContext. So you end up putting DbContext in a thin repository wrapper so you can easily test components later on.

I think it's worth mentioning that I have never used Repository pattern with NHibernate, because the session and session factory are interfaces - ISession and ISessionFactory accordingly.

If you use a repository by interface somewhere (IRepository) and inject it, the testing by mocking/stubbing will be much easier:

public class DinnerOperation
{
    private readonly IDinnerRepository repository;

    public DinnerOperation(IDinnerRepository dinnerRepository)
    {
        repository = dinnerRepository;
    }
}

Of course you'd have to use IoC container of choice to inject the right instance for you (DinnerRepository in this case), or do the DI 'by hand'.

That way you can test DinnerOperation class against mocked or stubbed repository. When you instantiate DbContext, you can't.

Patryk Ćwiek
  • 14,078
  • 3
  • 55
  • 76
  • Entity Framework IS mockable.... now. You are probably thinking of previous versions that made it incredibly painful to do so. Now, as you see in my post above, You can use an Interface (IDbContext) for the context instead of DbContext, thus allowing you to easiily test components. – Keith Mar 05 '13 at 16:29
  • @Keith true, it was painfully hard to do before. I must have missed the `IDbContext` interface, but thanks for the tip, I will explore the topic a little bit further. :) – Patryk Ćwiek Mar 05 '13 at 16:34
  • @Keith I can't find any notion of `IDbContext` interface being readily available in EF 5.0+. (There is `IDbSet` though) All I can find are custom-implemented solutions; if you have anything to point me towards the mentioned interface, I'd appreciate it. Of course if it's a custom-rolled solution, then I can do the same on my own ;) – Patryk Ćwiek Mar 05 '13 at 17:39