近来发现很多ASP.NET MVC的例子中都使用了Repository模式,比如Oxite,ScottGu最近发布的免费的ASP.NET MVC教程都使用了该模式。就简单看了下。
在《企业架构模式》中,译者将Repository翻译为资源库。给出如下说明:
通过用来访问领域对象的一个类似集合的接口,在领域与数据映射层之间进行协调。
在《领域驱动设计:软件核心复杂性应对之道》中,译者将Repository翻译为仓储,给出如下说明:
一种用来封装存储,读取和查找行为的机制,它模拟了一个对象集合。
使用该模式的最大好处就是将领域模型从客户代码和数据映射层之间解耦出来。
我们来看下在LinqToSql中如何应用该模式。
1. 我们将对实体的公共操作部分,提取为IRepository接口,比如常见的增加,删除等方法。如下代码:
interface IRepository<T> where T : class { IEnumerable<T> FindAll(Func<T, bool> exp); void Add(T entity); void Delete(T entity); void Save(); }
2.下面我们实现一个泛型的类来具体实现上面的接口的方法。
public class Repository<T> : IRepository<T> where T : class { public DataContext context; public Repository(DataContext context) { this.context = context; } public IEnumerable<T> FindAll(Func<T, bool> exp) { return context.GetTable<T>().Where(exp); } public void Add(T entity) { context.GetTable<T>().InsertOnSubmit(entity); } public void Delete(T entity) { context.GetTable<T>().DeleteOnSubmit(entity); } public void Save() { context.SubmitChanges(); } }
3.上面我们实现是每个实体公共的操作,但是实际中每个实体都有符合自己业务的逻辑。我们单独定义另外一个接口,例如:
interface IBookRepository : IRepository<Book> { IList<Book> GetAllByBookId(int id); }
4.最后该实体的Repository类实现如下:
public class BookRepository : Repository<Book>, IBookRepository { public BookRepository(DataContext dc) : base(dc) { } public IList<Book> GetAllByBookId(int id) { var listbook = from c in context.GetTable<Book>() where c.BookId == id select c; return listbook.ToList(); } }
上面只是为大家提供了一个最基本使用框架。
关于Repository模式
定义(来自Martin Fowler的《企业应用架构模式》):
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
个人理解:Repository是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。
1. Repository模式是架构模式,在设计架构时,才有参考价值;
2. Repository模式主要是封装数据查询和存储逻辑;
3. Repository模式实际用途:更换、升级ORM引擎,不影响业务逻辑;
4. Repository模式能提高测试效率,单元测试时,用Mock对象代替实际的数据库存取,可以成倍地提高测试用例运行速度。
评估:应用Repository模式所带来的好处,远高于实现这个模式所增加的代码。只要项目分层,都应当使用这个模式。
关于泛型Repository接口(来源):
仅使用泛型Repository接口并不太合适,因为Repository接口是提供给Domain层的操作契约,不同的entity对于Domain来说可能有不同的操作约束。因此Repository接口还是应该单独针对每个Eneity类来定义。
泛型的Repository<T>类仍然用来减少重复代码,只是不能被UserRepository类直接继承,因为这样Delete方法将侵入User类,所以改为在UserRepository中 组合一个Repository<T>,将开放给domain可见且又能使用泛型重用的功能委托给这个Repository<T>
Repository与Dal的区别(来源):
Repository是DDD中的概念,强调Repository是受Domain驱动的,Repository中定义的功能要体现Domain的意图和约束,而Dal更纯粹的就是提供数据访问的功能,并不严格受限于Business层。
使用Repository,隐含着一种意图倾向,就是 Domain需要什么我才提供什么,不该提供的功能就不要提供,一切都是以Domain的需求为核心;而使用Dal,其意图倾向在于我Dal层能使用的数 据库访问操作提供给Business层,你Business要用哪个自己选。换一个Business也可以用我这个Dal,一切是以我Dal能提供什么操 作为核心。
相关英文文章:
Using Repository and Unit of Work patterns with Entity Framework 4.0
Implementing Repository Pattern With Entity Framework
Using the Entity Framework Repository and UnitOfWork Pattern in C# ASP .NET
Revisiting the Repository and Unit of Work Patterns with Entity Framework
Do we need to use the Repository pattern when working in ASP.NET MVC with ORM solutions?
We have IQueryable, so why bother with a repository
Crazy Talk: Reducing ORM Friction
推荐代码示例:
Microsoft - Domain Oriented N-Layered .NET 4.0 App Sample (DDD Architecture)
相关博文:
EntityFramework之领域驱动设计实践(七)-模型对象的生命周期 - 仓储
EntityFramework之领域驱动设计实践(八)- 仓储的实现:基本篇
出自:
http://www.cnblogs.com/dudu/archive/2011/05/25/repository_pattern.html