2010-07-31 81 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接口...