Reputation: 15876
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?
Upvotes: 6
Views: 5885
Reputation: 1129
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).
Upvotes: 7
Reputation: 48314
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?
Upvotes: 7
Reputation: 14328
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.
Upvotes: 2