接口
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();
}
从上面的接口继承的类
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();
}
}
程序中的用法
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();
}
}
没有使用存储库设计模式......
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();
}
}
问题
我不明白,在这里,我们为什么要使用设计模式? 以这种方式使用具有实体框架的存储库设计模式并不意味着什么。
如何将设计模式与权利框架一起使用?何时将设计模式与实体框架结合使用是有意义的?
答案 0 :(得分:6)
你几乎得到了它。首先,重构您的晚餐操作类,以便可以将注册表实现注入其中。
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();
}
}
然后实现不同的存储库:
public class EntityFrameworkDinnerRepository : IDinnerRepository
public class NHibernateDinnerRepository : IDinnerRepository
public class Linq2SqlDinnerRepository : IDinnerRepository
public class MockDinnerRepository : IDinnerRepository
....
然后使用您想要的任何存储库:
var repository = new ....Repository();
var operation = new DinnerOperation( repository );
operation.GetDinner(5);
存储库用于抽象您的具体数据提供者,从而使您的架构更加可靠。
想切换到nHibernate吗?
痛苦,如果你到处都有EntityFramework。 很简单,如果您使用存储库,则只需注入另一个存储库,您的业务逻辑就不必更改。
想要对您的业务逻辑进行单元测试吗?
痛苦,如果你坚持使用具体的数据提供者。 很简单,如果你有存储库,你只需注入一个甚至不使用数据库的内存存储库。
现在知道了吗?
答案 1 :(得分:5)
我在使用ORM时拒绝使用存储库模式。我认为在这种情况下它几乎没有任何好处。 (是的,我希望狂热者投票约2000次)。
使用EF,我为我的Context
创建了一个界面public interface IDinnerContext : IDisposable
{
IDbSet<Dinner> Dinners;
int SaveChanges();
}
然后我将这个界面粘贴在我的EF DatabaseContext实现上,并且中提琴!我可以在任何地方使用EF,使用MOCK实现单元测试我的数据库访问,如果我愿意,可以使用注入,而不是最终使用600万个GetByXXX方法。 IQeryable处理它,我得到延迟执行。我真的不需要插入/删除方法,因为IDBSet已经有添加/删除。我有更清晰/更容易阅读的代码,抽象更少。
如果我有一个案例,在许多不同的地方使用相同的查询,我真的希望这是常见的,那么我可以添加一些机制来支持它。但是,95%的情况下,查询特定于负责业务逻辑X的组件(简单GetBy语句之外的任何内容)。所以我不认为这是一个问题。
不要误会我的意思,我虔诚地使用了存储库模式,直到ORM变得相当不错。一旦ORM达到一定程度的复杂程度,我觉得可能不再需要存储库模式,并且开始没有它的项目....并且永远不会回头看。我认为其他所有人最终都会朝这个方向发展,或者类似的东西,但旧的习惯会因此而死。 (我知道一些仍然坚持使用锁(这个)的开发人员,因为它仍然存在于某些MS样本中。)
答案 2 :(得分:2)
这是存储库模式,它本身对于实体框架来说是超级的,因为DbContext
同时充当了存储库和工作单元,但它不可模仿 - 有没有IDbContext
。因此,您最终将DbContext
放入精简存储库包装器中,以便稍后可以轻松地测试组件。
我认为值得一提的是我从未在NHibernate中使用Repository模式,因为会话和会话工厂都是接口 - ISession
和ISessionFactory
。
如果您通过某个地方的接口(IRepository
)使用存储库并将其注入,则通过模拟/存根进行测试会更容易:
public class DinnerOperation
{
private readonly IDinnerRepository repository;
public DinnerOperation(IDinnerRepository dinnerRepository)
{
repository = dinnerRepository;
}
}
当然,你必须使用选择的IoC容器为你注入正确的实例(在这种情况下为DinnerRepository
),或者手工执行DI'。
通过这种方式,您可以针对模拟或存根存储库测试DinnerOperation
类。当您实例化DbContext
时,您不能。