Repository模式完全實戰引發的思考

前言:
這個月請假出去玩了幾天,當了幾天文藝青年,回來之后任務稍微緊了一點。放松之后回歸正軌,好久沒寫了,也沒什么好的東西值得分享,對於之前的文章好多朋友留言了,看來博客園的同學們對於技術還是比較踏實的。關於其中的一些問題有的我沒有遇到過,我也不敢妄下斷言,還是希望大家能夠各種搜索自己解決吧。這篇簡單說說Repository帶來的思考吧。
什么是Repository模式:
其實在我們參考目前的C#框架或者代碼的時候,已經發現這種模式早已滲透到了C#項目開發與架構之中,就如同當年的三層架構上的DAL。
Repository與Dal的區別:
Repository是DDD中的概念,強調Repository是受Domain驅動的,Repository中定義的功能要體現Domain的意圖和約束。
Dal只是關心的DB。
如果不在項目中使用的話總感覺沒跟上潮流,許多文章對其最簡單的解釋是:
一種用來封裝存儲,讀取和查找行為的機制,它模擬了一個對象集合。
其實很多時候學習東西最快的方法就是:學以致用。知道什么之后,去用,在學,在重構,就OK了。
個人認為,Repository使用的如此廣泛得益於.net方向的ORM的繁榮,就是因為開發者拜托了最基本的SQL操作,將其交由ORM處理,開發人員才有更多的精力去研究與折騰我們關心的業務和邏輯。
Repository模式主要是封裝數據查詢和存儲邏輯。
當開發者減少了對SQL直接操作DB的依賴之后,他們就在考慮是否以同樣的方法去擺脫其他數據存儲介質的依賴,為了適配更多的數據媒介,就又提煉出了另一個Repository的特點,
Repository模式實際用途:更換、升級ORM引擎,不影響業務邏輯;
隨着開發者能力的提高經驗的提高,他們也面對着越來越多的業務分散的開發任務。比如做一個類似於Windows操作系統的軟件,我們之前期望以一種簡單線條去覆蓋所有開發任務的經驗變得不是那么的實際。隨之業務的獨特性與分散性,也許1-2個開發人員就需要去完成一個特定的模塊與功能,開發過程適配其他API的任務就會變得瑣碎。於是“單元測試”就變成了不可或缺的一部分,也就有了目前的“測試驅動”的開發策略,為實現能在最小的粒度,邊界去測試功能。就有了Repository的另一個特性,
Repository模式能提高測試效率,單元測試時,用Mock對象代替實際的數據庫存取,可以成倍地提高測試用例運行速度。
綜上所述,任何一個模式的誕生,都是體現了開發者的智慧,但是其核心仍是我們看了許久,但又感覺索然無味的面向對象的基本原則:
這是里子,面子怎么換是為了適應時代的變遷,我們期待改變,但又不能忘記最真的。
廢話扯了,上代碼:
IRepositoryBase:這是所有的基類
public interface IRepositoryBase { } public interface IRepositoryBase<TEntity> : IRepositoryBase where TEntity : class { TestEntities DBContext { get; set; } IQueryable<TEntity> GetQueryList(); IQueryable<TEntity> GetQueryList(Expression<Func<TEntity, bool>> predicate); IEnumerable<TEntity> GetList(); IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate); int GetCount(Expression<Func<TEntity, bool>> predicate); TEntity Get(Expression<Func<TEntity, bool>> predicate); void Add(TEntity entity); void Update(TEntity entity); void Delete(TEntity entity); void Save(); }
ILogFirewallRepository:一個為了適配自身業務的Repository
public interface ILogFirewallRepository : IRepositoryBase<LogFirewall> { void UpdateLogEPTables(int EPID, string preValue, string nowValue, string user); }
RepositoryBase:對於基類通用任務的實現
public abstract class RepositoryBase { protected TestEntities _dbContext; public TestEntities DBContext { get { return _dbContext; } set { _dbContext = value; } } /// <summary> /// /// </summary> public RepositoryBase() { _dbContext = new TestEntities(); } /// <summary> /// /// </summary> public virtual void Save() { _dbContext.SaveChanges(); } /// <summary> /// /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="sqlstr"></param> /// <param name="orderby">排序列</param> /// <param name="pageIndex">從1開始</param> /// <param name="pageCount"></param> /// <returns></returns> public IEnumerable<TEntity> GetPaging<TEntity>(string sqlstr, string orderby, int pageIndex, int pageCount, params object[] parameters) where TEntity : class { int start = 1; int end = PageConfig.PageSize; if (pageIndex > 0 && pageCount > 0) { start = pageCount * (pageIndex - 1) + 1; end = pageCount * ((pageIndex - 1) + 1); } Regex order = new Regex("-(asc|desc)$", RegexOptions.IgnoreCase); if (order.IsMatch(orderby)) { orderby = order.Replace(orderby, " $1"); } string sql = string.Format(@" SELECT * FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY {1} ) AS RowNumber, * FROM ({0} ) A_ ) AS A1_ WHERE RowNumber BETWEEN {2} AND {3} ORDER BY {1} ;" , sqlstr, orderby, start, end ); return _dbContext.Set<TEntity>().SqlQuery(sql, parameters); } } public class SyncRepositoryBase<TEntity> : RepositoryBase, IRepositoryBase<TEntity> where TEntity : class { IDbSet<TEntity> _dbSet; public SyncRepositoryBase() { this._dbSet = _dbContext.Set<TEntity>(); } public SyncRepositoryBase(TestEntities context) { this._dbContext = context; this._dbSet = this._dbContext.Set<TEntity>(); } public virtual IEnumerable<TEntity> GetList() { return _dbSet.ToList(); } public virtual IQueryable<TEntity> GetQueryList() { return _dbSet; } public virtual IQueryable<TEntity> GetQueryList(Expression<Func<TEntity, bool>> predicate) { return _dbSet.Where(predicate); } public virtual IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate) { return _dbSet.Where(predicate).ToList(); } public virtual int GetCount(Expression<Func<TEntity, bool>> predicate) { return _dbSet.Where(predicate).Count(); } public virtual TEntity Get(System.Linq.Expressions.Expression<Func<TEntity, bool>> predicate) { return _dbSet.Where(predicate).FirstOrDefault(); } public virtual void Add(TEntity entity) { _dbSet.Add(entity); } public virtual void Update(TEntity entity) { _dbContext.Entry(entity).State = EntityState.Modified; } public virtual void Delete(TEntity entity) { _dbSet.Remove(entity); } ///// <summary> ///// ///// </summary> //public virtual void Save() //{ // _dbContext.SaveChanges(); //} }
LogFirewallRepository:對自身業務的實現
public class LogFirewallRepository : SyncRepositoryBase<LogFirewall>, ILogFirewallRepository { public LogFirewallRepository() { } public LogFirewallRepository(TestEntities context) : base(context) { } public void UpdateLogEPTables(int EPID, string preValue, string nowValue, string user) { //update the logFireWall table var log = this.DBContext.LogFirewall as IQueryable<LogFirewall>; LogFirewall logEP = new LogFirewall() { Previous = preValue, After = nowValue, Handler = user, HandledDate = DateTime.Now, FirewallID = EPID }; this.Add(logEP); this.Save(); } }
在Repository之上習慣加入Service進行業務聚合(和Domain沒關系)
IMQMessageService:提煉自身聚合任務
public interface IMQMessageService { void InsertANewMessage(Message message); }
ServicesBase<TEntity>:一些通用聚合任務的實現
public interface ServicesBase<TEntity> { IQueryable<TEntity> GetQueryList(); IQueryable<TEntity> GetQueryList(Expression<Func<TEntity, bool>> predicate); IEnumerable<TEntity> GetList(); IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate); int GetCount(Expression<Func<TEntity, bool>> predicate); TEntity Get(Expression<Func<TEntity, bool>> predicate); void Add(TEntity entity); void Update(TEntity entity); void Delete(TEntity entity); void Save(); }
MQMessageService:自身聚合任務實現
public class MQMessageService : ServicesBase<Message>, IMQMessageService { IMQMessageRepository msR = new MQMessageRepository(); public void InsertANewMessage(Message message) { msR.Add(message); msR.Save(); } }
以上只是最簡單的Repository的使用,在不同業務需求與開發重點側重不同的情況下,實現方式與封裝使用也會不同。因為我這里的業務應該是后面的線程協調與資源並發處理,所以這里用到最簡單就可以了。