这次我有一个更哲学的问题。
大多数MVC教程/书籍似乎建议将一个存储库的范围限制为模型的一个方面,并设置多个存储库以涵盖所有模型类。 (例如:ProjectRep,UserRep,ImageRep,最终都映射到同一个数据库。)
我可以看到这将如何使单元测试更简单但我无法想象这将如何在现实世界中起作用,在现实世界中大多数实体之间具有相互关系。最后,我总是发现自己每个数据库连接都有一个巨大的存储库类,并且用于单元测试的同样是一个笨拙的FakeRepository。
那么,你有什么看法?我应该更加努力地分离出存储库吗?是否ProductRep通过PurchaseHistory引用UserRep中的数据,反之亦然?当访问单个数据库时,不同的代表如何确保它们不会互相锁定?
谢谢, 达菲
答案 0 :(得分:3)
这在现实世界中有效,因为存储库内有单引擎。这可以是像NHibernate或您自己的解决方案的ORM。该引擎知道如何关联对象,锁定数据库,缓存请求等。但业务代码不应该知道这些基础结构细节。
当您最终获得一个giantic存储库时,您实际上做的是将此单引擎暴露给现实世界。因此,您会使用特定于引擎的详细信息来破坏域代码,否则这些详细信息将隐藏在存储库接口之后。
S#arp Architecture非常好地说明了Josh谈论的存储库是如何实现和工作的。另请阅读NHibernate最佳实践article,它解释了S#arp背景的大部分内容。
坦率地说,我无法想象你的giantic存储库在现实世界中如何运作。因为这个想法看起来很糟糕且不可维护。
答案 1 :(得分:2)
我发现通过使用泛型和接口,您可以避免编写许多单独的存储库。如果您的域模型是一个很好的因素,您通常可以使用域对象而不是另一个存储库来导航对象图。
public class MyDomainObject : IEntity //IEntity is an arbitrary interface for base ents
{
public int Id { get; set;}
public List<DiffObj> NavigationProp { get; set;}
//... and so on...
}
public interface IRepository<T> where T : IEntity, class, new()
{
void Inert(T entity);
T FindById(int id);
//... and so on
}
用法非常简单,通过使用IoC,您可以完全将实现与应用程序的其余部分分离:
public class MyBusinessClass
{
private IRepository<SomeDomainObject> _aRepo;
public MyBusinessClass(IREpository<SomeDomainObject> aRepo)
{
_aRepo = aRepo;
}
//...and so on
}
这使得编写单元测试变得非常简单。