2010-07-31 84 views
12

我正在寻找在一个小项目中使用IRepository模式(由NHibernate支持,如果它很重要)。这个域是一个简单的域,故意让我专注于理解IRepository模式。单独域名类别为Movie,属性为YearGenreTitle。我的意图是“获得”电影的属性符合上述类型的标准。我正确使用IRepository吗?

公约似乎有一个通用的IRepository接口,类似于以下内容:

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

有了基本实现:

public abstract class Repository<T> : IRepository<T> 
{ 
    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<Movie>, IMovieRepository 
{ 
    public Movie[] GetByGenre(Genre genre) { ... } 
    public Movie[] GetByYear(int year) { ... } 
    public Movie[] GetByTitle(string title) { ... } 
} 

我需要必要的执行添加到基类以及具体的一个,使用NHibernate的,但我想知道如果我在正确的轨道与此设置上。

对于只有一个域类而言似乎存在一点点的开销,但是如果涉及多个域类,它将不太明显。现在我正在努力保持简单,以便我可以确定这个概念。

回答

2

我说,你是接近我在交通运输企业(使用NHibernate以及)对资源规划生产解决方案使用的存储库 - 所以对于初学者来说你是正确的在我看来的路径。我同意使用IEnumerables/IList而不是数组来使用dbones--你最终会在.-Array()上写下多次:-)。

有几件事情,你可能会考虑:

青睐组成了传承 - 而不是从抽象库继承 - 让它成为非抽象并在“构造函数注入,并委托电话 - 这使得您的设计在某些情况下更强大(例如,仅用于仅查询存储库等)。这样,您还可以选择让抽象存储库可实例化(是否是一个词?)并控制是否应该在所有存储库中共享该存储库。

跟进这一点 - 您可能要更改基本信息库拥有的,而不是从通用接口继承泛型方法:

public class Repository 
{ 
    public void Add<T>(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<T> WrapQueryInSession<T>(Func<ISession,IList<T> 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<Movie> GetByYear(int year) 
    { 
     Func<ISession, IList<Movie> query = session => 
     { 
      var query = session.CreateQuery("from Movie"); //or 
      var query = session.CreateCriteria("from Movie"); //or 
      var query = session.Linq<Movie>(); 
      //set criteria etc. 
      return query.List<Movie>(); //ToList<Movie>() if you're using Linq2NHibernate 
     }: 
     return _repository.WrapQueryInSession(query); 
    } 
} 

您可能还希望,如果出现上设置你的方法一个布尔返回值错误 - 也许一出IEnumerable的任何错误,这将使感调用代码。

但总而言之 - 这些只是我随着时间的推移而添加的,以便更好地遵守我的使用习惯 - 而且它们完全是可选的,仅供参考:-)。我认为你走在正确的道路上 - 我的代码中没有看到任何重大问题。

希望这是有道理:-)

+0

我喜欢你的建议,使用非抽象的'Repository'来处理从特定回购委托授权的通用低级CRUD类型的工作。它的确提出了将'ISession'用于通用回购和使用它的特定回购的问题。 – 2010-08-03 15:26:26

+0

ISession应该通过Repository中的私有ISessionFactory获取。具体的存储库然后使用通用存储库的WrapxxxInSession方法。 – Goblin 2010-08-03 16:57:59

+0

啊,是的,这有帮助。我非常喜欢整体想法......另一个好处是注入的IRepository可以被模拟进行测试。将会有按照正确的顺序构造和传递对象的技巧,但IoC工具可能会处理它。 – 2010-08-03 17:13:55

6
  1. 尽量不要传回array。使用IEnumerable<T>ICollection<T>IList<T>,这将松散地耦合您的代码。

  2. 您的IMovieRepository接口。此存储库包含CRUD。因此使得

IMovieRepository : IRepository<Movie> {}

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

终于。这对于其中一种方法来说很好。由于您具有专门的功能,因此您需要专门设计适合的存储库

还有其他一些方法,它们使您能够使用1个存储类并传递所需的查询。这被称为规范模式。我做了一个项目,使用这个位于codeplex与报告http://whiteboardchat.codeplex.com

另一种方式将有一个方法传递的标准。有一个名为夏普体系结构的开源项目,我相信这已经编码了。

希望这有助于

+0

感谢指定模式实现指针和基于标准的方法。两者都是有趣的想法,我会仔细观察它们,尽管现在我将事情简单明了。 – 2010-08-03 15:33:21

0

至于深思,如果你选择的ORM有LINQ提供程序(和NH有一个),你可以尝试可查询的资料库是非常相似的集合:

public interface IRepository<T> : ICollection<T>, IQueryable<T> 

我已经写了一些关于它在我的网站:Repository or DAO?: Repository 它有相似之处的建设(仅仅因为一个集合支持CRUD为好),我会尝试的方法意味着你可以有代码,不一定知道处理存储库,因为它可以编程为ICollectionIQueryable接口...