C# 方法的存储库模式标准化
我只是想找出存储库模式的正确定义 我最初的理解是这样的(极度沉默)C# 方法的存储库模式标准化,c#,design-patterns,repository-pattern,C#,Design Patterns,Repository Pattern,我只是想找出存储库模式的正确定义 我最初的理解是这样的(极度沉默) 将业务对象与数据对象分开 标准化数据访问层中的访问方法 我真的看到了两种不同的实现,网上没有正式的例子,我看到的都藏在书中 实施1: public Interface IRepository<T>{ List<T> GetAll(); void Create(T p); void Update(T p); } public interface IProductR
- 将业务对象与数据对象分开
- 标准化数据访问层中的访问方法
public Interface IRepository<T>{
List<T> GetAll();
void Create(T p);
void Update(T p);
}
public interface IProductRepository: IRepository<Product> {
//Extension methods if needed
List<Product> GetProductsByCustomerID();
}
public interface IProductRepository {
List<Product> GetAllProducts();
void CreateProduct(Product p);
void UpdateProduct(Product p);
List<Product> GetProductsByCustomerID();
}
公共接口IRepository{
List GetAll();
无效创建(tp);
无效更新(tp);
}
公共接口IPProductRepository:IRepository{
//扩展方法(如果需要)
列出GetProductsByCustomerID();
}
实施2:
public Interface IRepository<T>{
List<T> GetAll();
void Create(T p);
void Update(T p);
}
public interface IProductRepository: IRepository<Product> {
//Extension methods if needed
List<Product> GetProductsByCustomerID();
}
public interface IProductRepository {
List<Product> GetAllProducts();
void CreateProduct(Product p);
void UpdateProduct(Product p);
List<Product> GetProductsByCustomerID();
}
公共接口存储库{
列出GetAllProducts();
无效产品(产品p);
作废更新产品(产品p);
列出GetProductsByCustomerID();
}
请注意,第一个是通用的Get/Update/GetAll,等等,第二个更像我定义的“DAO”
两者都共享从数据实体中提取的内容。我喜欢,但是我可以用一把简单的刀。然而,我认为第二部分标准化访问操作很有价值,如果您在整个企业范围内实现这一点,人们将很容易了解存储库的访问方法集
我是否错误地认为数据访问的标准化是这种模式的一个组成部分?如果两者都正确,为什么要选择执行2
有一篇关于实现1的好文章,当然MS有一个含糊不清的例子,实现2的一个例子是。来自Martin Fowler的“企业应用程序架构模式”,存储库模式的定义是:
使用用于访问域对象的类似集合的接口在域和数据映射层之间进行调解
所以,这两种方法都是正确的。 < P>我是通用知识库模式的一个狂热爱好者,但我认为您应该强烈地考虑不直接从接口继承,因为它可以成为一个很大的限制,特别是因为很多时候,通用接口的代码将与在抽象基类中定义的相同。一个类中的泛型存储库将不能超过1个 我建议您的IPProductRepository实现者通过委托访问泛型的
IRepository
,并通过构造函数将其注入,这样您就可以组合可能包含许多IRepository的类,并以合理的方式将它们分组到单个接口后面
我写了一篇关于这个主题的博客,其中特别提到了NHibernate。这个模式可以应用于任何类型的存储库:随着.NET中LINQ的引入,通用存储库模式变得更容易实现:
public interface IRepository<T> : IQueryable<T>
{
void Add(T item);
void Remove(T item);
}
公共接口IRepository:IQueryable
{
无效添加(T项);
消除无效(T项);
}
要获得存储库的资格,它只需要能够访问底层存储中的数据(由IQueryable
轻松提供)并修改包含的数据
您可以提供对基本接口的扩展,以便为更多特定于实体的行为(例如连接到基于SQL的存储库的存储过程调用)提供钩子,但大多数操作都可以通过简单的接口完成。我支持oded引用的Fowler引语。我想指出的是,他所说的“收藏式”界面。如何实现类似集合的接口当然取决于您,但您既不能也不应该试图隐藏它表示远程数据源的事实。因此,它与内存中的集合有很大不同,内存中的集合不需要刷新对远程数据存储的更改。ORM或roll your own解决方案的更改跟踪机制决定了对调用方的透明程度。删除通常需要显式标记,插入是可发现的(通过可达性持久化),更新有时也需要显式标记。将这一点与聚合根的复杂依赖关系结合起来,您会发现这与集合不太相似 没有所谓的“cannonical存储库实现” 泛型存储库基类的拥护者和喜欢自己实现每个存储库的人之间一直在进行斗争。虽然通用实现在简单场景中很有吸引力,但您经常会发现它是一个非常容易泄漏的抽象。例如,某些聚合可能只被软删除(可通过虚拟方法重写进行cistomizable),而其他聚合可能根本不支持删除操作 在决定采取哪种方法之前,请确保您了解每种方法的含义。Greg Young在通用存储库的优点方面发表了一篇很好的文章
除了通用的存储库接口(实现1)和您在特定于角色的存储库(实现2)的变体之外,还可以考虑一个泛型方法库:
public interface IRepository
{
void Save<ENTITY>(ENTITY entity) where ENTITY : DomainEntity;
ENTITY Load<ENTITY>(Guid id) where ENTITY : DomainEntity;
IQueryable<ENTITY> Query<ENTITY>() where ENTITY : DomainEntity;
IQueryable<ENTITY> Query<ENTITY>(IDomainQuery<ENTITY> whereQuery)
where ENTITY : DomainEntity;
}
公共接口IRepository
{
作废保存(实体实体),其中实体:DomainEntity;
实体加载(Guid id),其中实体:DomainEntity;
IQueryable Query(),其中实体:DomainEntity;
IQueryable查询(IDomainQuery whereQuery)
其中实体:域实体;
}
第三个版本来自Jimmy Bogard,他还表示更喜欢通用存储库接口。
我通常使用实现此接口的通用存储库基类来遵循这一点;这样,我只需要为每个域实体实现不同的东西 我通常使用具有组合而不是继承的通用存储库。这给了我通用实现的优势,它可以控制要公开哪些方法 大概是这样的:
public Interface IRepository<T>{
List<T> GetAll();
void Create(T p);
void Update(T p);
}
public interface IProductRepository {
//Extension methods if needed
List<Product> GetProductsByCustomerID();
List<T> GetAll();
void Create(T p);
//Let assume here you should not be able to update the products
}
public ProductRepository : IProductRepository {
private IRepository _repository;
public ProductRepository(IRepository repository) {
this._repository = repository;
}
List<T> GetAll()
{
_repository.GetAll();
}
void Create(T p)
{
_repository.Create(p);
}
List<Product> GetProductsByCustomerID()
{
//..implementation goes here
}
}
pu