簡體   English   中英

我正確使用IRepository嗎?

[英]Am I using IRepository correctly?

我想在一個小項目中使用IRepository模式(由NHibernate支持,如果它很重要)。 域是一個簡單的域,故意讓我專注於理解IRepository模式。 單獨的域類是Movie ,具有YearGenreTitle屬性。 我的意圖是“獲取”其屬性符合上述類型標准的電影。

慣例似乎是具有通用的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添加必要的實現到基類以及具體的實現,但我想知道我是否在這個設置的正確軌道上。

對於一個域類似乎有相當大的開銷,但如果涉及多個域類則不太明顯。 現在我正試圖保持簡單,所以我可以確定這個概念。

  1. 盡量不要傳回一個array 使用IEnumerable<T>ICollection<T>IList<T> ,這將進一步松散地耦合您的代碼。

  2. 你的IMovieRepository接口。 此存儲庫包括CRUD。 因此成功

IMovieRepository : IRepository<Movie> {}

這不會改變您的MovieRepository類,因為它將正確實現接口。 如果您希望在以后更改實施,它將允許您解耦您的課程。

最后。 這對其中一種方法來說很好。 因為你有專門的功能,你已經專門設置了適合的存儲庫。

還有其他方法,使您可以使用1個repositry類並傳遞所需的查詢。 這稱為規范模式。 我做了一個項目,使用它位於codeplex上,報告http://whiteboardchat.codeplex.com

另一種方法是有一個方法來傳遞標准。 有一個名為Sharp Architecture的開源項目,我認為這個編碼了。

希望這可以幫助

我會說,你接近我在生產解決方案中使用的存儲庫,用於運輸公司的資源規划(也使用NHibernate) - 所以對於初學者來說,在我看來你是正確的道路。 我同意dbones使用IEnumerables / IList而不是數組 - 你最終會多次編寫.ToArray():-)。

您可以考慮以下幾點:

優先於繼承 - 而不是繼承自抽象存儲庫 - 讓它是非抽象的並將其注入'ctor並委托調用 - 這使得您的設計在某些情況下更加健壯(例如,對於僅查詢存儲庫等。那么你也可以選擇讓抽象存儲庫可以實例化(是一個單詞嗎?)並控制它是否應該在所有存儲庫中共享。

關注這一點 - 您可能希望更改基本存儲庫以使用通用方法,而不是從通用接口繼承:

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);
    }
}

如果出現問題,您可能還想在方法上設置bool返回值 - 對於在調用代碼中有意義的任何錯誤,可能需要輸出IEnumerable。

但總而言之 - 這些只是我隨着時間的推移而增加的花絮,以更好地遵守我的用法 - 它們完全是可選的,只是值得思考的食物:-)。 我認為你走的是正確的道路 - 我沒有看到你的代碼中有任何重大問題。

希望這是有道理的:-)

作為思考的食物,如果您選擇的ORM具有LINQ提供程序(並且NH有一個),您可以嘗試與集合非常相似的可查詢存儲庫:

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

我在我的網站上寫了一些關於它的內容: 存儲庫或DAO?:存儲庫它與你的構造有相似之處(僅僅因為集合也支持CRUD),我嘗試的方法意味着你可以擁有不一定知道的代碼處理存儲庫,因為它可以針對ICollectionIQueryable接口進行編程...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM