我正确使用IRepository吗?

我想在一个小项目中使用IRepository模式(由NHibernate支持,如果重要的话)。 域是一个简单的域,故意让我专注于理解IRepository模式。 单独的域类是Movie ,具有YearGenreTitle属性。 我的目的是“获取”其属性符合上述类型标准的电影。

惯例似乎是有一个通用的IRepository接口,类似于以下内容:

 public interface IRepository { T Get(int id); T[] GetAll(); void Add(T item); void Update(T item); void Delete(T item); } 

有了基础实现:

 public abstract class Repository : IRepository { public T Get(int id) { ... } public T[] GetAll() { ... } public void Add(T item) { ... } public void Update(T item) { ... } public void Delete(T item) { ... } } 

然后有一个特定于域的接口:

 public interface IMovieRepository { Movie[] GetByGenre(Genre genre); Movie[] GetByYear(int year); Movie[] GetByTitle(string title); } 

使用也扩展基本Repository类的实现:

 public class MovieRepository : Repository, IMovieRepository { public Movie[] GetByGenre(Genre genre) { ... } public Movie[] GetByYear(int year) { ... } public Movie[] GetByTitle(string title) { ... } } 

我需要使用NHibernate将必要的实现添加到基类以及具体的实现,但我想知道我是否在这个设置的正确轨道上。

对于一个域类似乎有相当大的开销,但如果涉及多个域类则不太明显。 现在我正在努力保持简单,所以我可以确定这个概念。

我会说,你接近我在生产解决方案中使用的存储库,用于运输公司的资源规划(也使用NHibernate) – 所以对于初学者来说,在我看来你是在正确的道路上。 我同意使用IEnumerables / IList而不是数组的dbones – 你最终会多次编写.ToArray():-)。

您可能会考虑以下几点:

优先于inheritance – 而不是inheritance自抽象存储库 – 让它是非抽象的并将其注入’ctor并委托调用 – 这使得您的设计在某些情况下更加健壮(例如,对于仅查询存储库等。这样你也可以选择让抽象存储库可以实例化(是一个单词吗?)并控制它是否应该在所有存储库中共享。

关注这一点 – 您可能希望更改基本存储库以使用通用方法而不是从通用接口inheritance:

 public class Repository { public void Add(T entity) { using(var session = GetSession()) using(var tx = session.BeginTransaction()) { session.Save(entity) //Transaction handling etc. } } .... //repeat ad nasseum :-) } 

您可能希望让特定的存储库可以访问ISession – 这极大地提高了您查询和控制渴望/延迟获取的灵活性,并充分利用了NHibernate等。

 public class Repository { public IList WrapQueryInSession(Func query) { using(var session = GetSession()) using(var tx = session.BeginTransaction()) { var items = query(session); //Handle exceptions transacitons etc. return items; } } } 

用法:

 public class MovieRepository : IMovieRepository { private Repository _repository; public MovieRepository(Repository repository) { _repository = repository; } public IList GetByYear(int year) { Func query = session => { var query = session.CreateQuery("from Movie"); //or var query = session.CreateCriteria("from Movie"); //or var query = session.Linq(); //set criteria etc. return query.List(); //ToList() if you're using Linq2NHibernate }: return _repository.WrapQueryInSession(query); } } 

如果出现问题,您可能还希望在方法上设置bool返回值 – 对于在调用代码中有意义的任何错误,可能需要输出IEnumerable。

但总而言之 – 这些只是我随着时间的推移而添加的花絮,以更好地遵守我的用法 – 它们完全是可选的,只是值得思考的食物:-)。 我认为你走的是正确的道路 – 我没有看到你的代码中出现任何重大问题。

希望这是有道理的:-)

  1. 尽量不要传回一个array 。 使用IEnumerableICollectionIList ,这将进一步松散地耦合您的代码。

  2. 您的IMovieRepository接口。 此存储库包括CRUD。 因此成功

IMovieRepository : IRepository {}

这不会改变您的MovieRepository类,因为它将正确实现接口。 如果您希望在以后更改实施,它将允许您解耦您的课程。

最后。 这对其中一种方法来说很好。 因为你有专门的function,所以你专门设置了适合的存储库。

还有其他方法,使您可以使用1个repositry类并传递所需的查询。 这称为规范模式。 我做了一个项目,使用它位于codeplex上,报告http://whiteboardchat.codeplex.com

另一种方法是有一个方法来传递标准。 有一个名为Sharp Architecture的开源项目,我认为这个编码了。

希望这可以帮助

作为思考的食物,如果你选择的ORM有LINQ提供者(NH有一个),你可以尝试与集合非常相似的可查询存储库:

 public interface IRepository : ICollection, IQueryable 

我在我的网站上写了一些关于它的内容: 存储库或DAO?:存储库它与你的构造有相似之处(仅仅因为集合也支持CRUD),我尝试的方法意味着你可以拥有不一定知道的代码处理存储库,因为它可以针对ICollectionIQueryable接口进行编程…