[英]Am I using IRepository correctly?
我想在一個小項目中使用IRepository模式(由NHibernate支持,如果它很重要)。 域是一個簡單的域,故意讓我專注於理解IRepository模式。 單獨的域類是Movie
,具有Year
, Genre
和Title
屬性。 我的意圖是“獲取”其屬性符合上述類型標准的電影。
慣例似乎是具有通用的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添加必要的實現到基類以及具體的實現,但我想知道我是否在這個設置的正確軌道上。
對於一個域類似乎有相當大的開銷,但如果涉及多個域類則不太明顯。 現在我正試圖保持簡單,所以我可以確定這個概念。
盡量不要傳回一個array
。 使用IEnumerable<T>
, ICollection<T>
或IList<T>
,這將進一步松散地耦合您的代碼。
你的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),我嘗試的方法意味着你可以擁有不一定知道的代碼處理存儲庫,因為它可以針對ICollection
或IQueryable
接口進行編程...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.