Respository模式在示例中的實際目的小結一下
- Repository模式是架構模式,在設計架構時,才有參考價值;
- Repository模式主要是封裝數據查詢和存儲邏輯;
- Repository模式實際用途:更換、升級ORM 引擎,不影響業務邏輯;
- Repository模式能提高測試效率,單元測試時,用Mock對象代替實際的數據庫存取,可以成倍地提高測試用例運行速度。
Repository與Dal的區別
Repository是DDD中的概念,強調Repository是受Domain驅動的,Repository中定義的功能要體現Domain的意圖和約束,而Dal更純粹的就是提 供數據訪問的功能,並不嚴格受限於Business層。
使用Repository,隱含着一種意圖傾向,就是 Domain需要什么我才提供什么,不該提供的功能就不要提供,一切都是以Domain的需求為核心;而使用Dal,其意圖傾向在於我Dal層能使用的數 據庫訪問操作提供給Business層,你Business要用哪個自己選。換一個Business也可以用我這個Dal,一切是以我Dal能提供什么操 作為核心。
LCLFramework框架之Repository模式設計
LCLFramework框架之Repository模式設計主要是參考http://apworks.codeplex.com/ 框架而來的,目前我只是擴展了LCL.Repositories.EntityFramework倉庫,對於個人來使用已經足夠了。
LCLFramework框架之Repository模式設計代碼
public interface IRepository<TEntity> where TEntity : class, IEntity { IRepositoryContext Context { get; } void Create(TEntity entity); void Delete(TEntity entity); void Update(TEntity entity); IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate); IEnumerable<TEntity> GetAll(PagingInfo paging = null); TEntity GetByKey(params object[] keyValues); IEnumerable<TEntity> GetPage(Expression<Func<TEntity, bool>> predicate,PagingInfo paging); } public interface IRepositoryContext : IUnitOfWork, IDisposable { Guid ID { get; } void RegisterNew(object obj); void RegisterModified(object obj); void RegisterDeleted(object obj); } public interface IUnitOfWork { bool DistributedTransactionSupported { get; } bool Committed { get; } void Commit(); void Rollback(); } /* 職責: 1:定義一個“倉庫”基類 2:與WCF交互,Repository<TEntity>類的紅色部分是與WCF交互的代碼。通過“數據門戶”來決定是本地執行還是網絡執行。 */ public abstract partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity { /// <summary> /// 是否聲明本倉庫為本地倉庫(客戶端只在客戶端查詢,服務端在服務端查詢) /// </summary> public DataPortalLocation DataPortalLocation { get; protected set; } private readonly IRepositoryContext context; public Repository(IRepositoryContext context) { this.context = context; this.DataPortalLocation = DataPortalLocation.Dynamic; } public IRepositoryContext Context { get { return this.context; } } #region IRepositoryContext #region CUD protected abstract void DoAdd(TEntity entity); protected abstract void DoRemove(TEntity entity); protected abstract void DoUpdate(TEntity entity); [Obfuscation] public void Create(TEntity entity) { this.FetchList(entity, "DoAdd"); } public void Delete(TEntity entity) { this.FetchList(entity, "DoRemove"); } public void Update(TEntity entity) { this.FetchList(entity, "DoUpdate"); } #endregion #region Query protected abstract IEnumerable<TEntity> DoGetAll(PagingInfo paging); protected abstract IEnumerable<TEntity> DoGet(Expression<Func<TEntity, bool>> predicate); protected abstract TEntity DoGetByKey(params object[] keyValues); protected abstract IEnumerable<TEntity> DoGetPage(Expression<Func<TEntity, bool>> predicate, PagingInfo paging); public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> predicate) { var list = this.FetchList(predicate, "DoGet"); return list; } public IEnumerable<TEntity> GetAll(PagingInfo paging=null) { var list = this.FetchList(paging, "DoGetAll"); return list; } public TEntity GetByKey(params object[] keyValues) { var list = this.FetchFirst(keyValues, "GetByKey"); return list; } public IEnumerable<TEntity> GetPage(Expression<Func<TEntity, bool>> predicate,PagingInfo paging=null) { return this.FetchList(paging, "GetPage"); } #endregion #endregion #region 獲取對象接口方法 protected TEntityList FetchListCast<TEntityList>(object criteria, string methodName) where TEntityList : class, IEnumerable<TEntity> { return this.FetchList(criteria, methodName) as TEntityList; } protected TEntity FetchFirstAs(object criteria, string methodName) { return this.FetchFirst(criteria,methodName) as TEntity; } protected IEnumerable<TEntity> FetchList(object criteria, string methodName) { // 調用 " 數據門戶 " var list = DataPortalApi.Action(this.GetType(), methodName, criteria, this.DataPortalLocation) as IEnumerable<TEntity>; return list; } protected TEntity FetchFirst(object criteria, string methodName) { var list = this.FetchList(criteria, methodName); var last = list.DefaultIfEmpty<TEntity>() as TEntity; return list.Count() > 0 ? last : null; } #endregion } public abstract class RepositoryContext :DisposableObject,IRepositoryContext { #region Private Fields private readonly Guid id = Guid.NewGuid(); private readonly ThreadLocal<List<object>> localNewCollection = new ThreadLocal<List<object>>(() => new List<object>()); private readonly ThreadLocal<List<object>> localModifiedCollection = new ThreadLocal<List<object>>(() => new List<object>()); private readonly ThreadLocal<List<object>> localDeletedCollection = new ThreadLocal<List<object>>(() => new List<object>()); private readonly ThreadLocal<bool> localCommitted = new ThreadLocal<bool>(() => true); #endregion #region Protected Properties protected IEnumerable<object> NewCollection { get { return localNewCollection.Value; } } protected IEnumerable<object> ModifiedCollection { get { return localModifiedCollection.Value; } } protected IEnumerable<object> DeletedCollection { get { return localDeletedCollection.Value; } } #endregion #region Protected Methods protected void ClearRegistrations() { this.localNewCollection.Value.Clear(); this.localModifiedCollection.Value.Clear(); this.localDeletedCollection.Value.Clear(); } #endregion #region IRepositoryContext Members public Guid ID { get { return id; } } public virtual void RegisterNew(object obj) { localNewCollection.Value.Add(obj); Committed = false; } public virtual void RegisterModified(object obj) { if (localDeletedCollection.Value.Contains(obj)) throw new InvalidOperationException("The object cannot be registered as a modified object since it was marked as deleted."); if (!localModifiedCollection.Value.Contains(obj) && !localNewCollection.Value.Contains(obj)) localModifiedCollection.Value.Add(obj); Committed = false; } public virtual void RegisterDeleted(object obj) { if (localNewCollection.Value.Contains(obj)) { if (localNewCollection.Value.Remove(obj)) return; } bool removedFromModified = localModifiedCollection.Value.Remove(obj); bool addedToDeleted = false; if (!localDeletedCollection.Value.Contains(obj)) { localDeletedCollection.Value.Add(obj); addedToDeleted = true; } localCommitted.Value = !(removedFromModified || addedToDeleted); } #endregion #region IUnitOfWork Members public virtual bool DistributedTransactionSupported { get { return false; } } public virtual bool Committed { get { return localCommitted.Value; } protected set { localCommitted.Value = value; } } public abstract void Commit(); public abstract void Rollback(); #endregion protected override void Dispose(bool disposing) { if (disposing) { this.localCommitted.Dispose(); this.localDeletedCollection.Dispose(); this.localModifiedCollection.Dispose(); this.localNewCollection.Dispose(); } } }
LCLFramework框架之Repository擴展
public class EntityFrameworkRepository<TEntity> : Repository<TEntity> where TEntity : class, IEntity { private readonly IEntityFrameworkRepositoryContext efContext; public EntityFrameworkRepository(IRepositoryContext context) : base(context) { if (context is IEntityFrameworkRepositoryContext) this.efContext = context as IEntityFrameworkRepositoryContext; } protected override void DoAdd(TEntity entity) { efContext.RegisterNew(entity); } protected override void DoRemove(TEntity entity) { efContext.RegisterDeleted(entity); } protected override void DoUpdate(TEntity entity) { efContext.RegisterModified(entity); } protected override IEnumerable<TEntity> DoGetAll(PagingInfo paging) { if (paging != null) { paging.TotalCount = efContext.Context.Set<TEntity>().Count(); return efContext.Context.Set<TEntity>().OrderBy(t => t.ID).Skip(paging.PageNumber - 1 * paging.PageSize).Take(paging.PageSize).ToList(); } else { return efContext.Context.Set<TEntity>().ToList(); } } protected override IEnumerable<TEntity> DoGet(Expression<Func<TEntity, bool>> predicate) { return efContext.Context.Set<TEntity>().Where(predicate).ToList(); } protected override TEntity DoGetByKey(params object[] keyValues) { return efContext.Context.Set<TEntity>().Find(keyValues); } protected override IEnumerable<TEntity> DoGetPage(Expression<Func<TEntity, bool>> predicate, PagingInfo paging = null) { if (paging != null) { paging.TotalCount = efContext.Context.Set<TEntity>().Count(); return efContext.Context.Set<TEntity>().OrderBy(predicate).Skip((paging.PageNumber - 1) * paging.PageSize).Take(paging.PageSize).ToList(); } else { return efContext.Context.Set<TEntity>().OrderBy(predicate).ToList(); } } } public interface IEntityFrameworkRepositoryContext : IRepositoryContext { DbContext Context { get; } } public class EntityFrameworkRepositoryContext : RepositoryContext, IEntityFrameworkRepositoryContext { #region Private Fields private readonly DbContext efContext; private readonly object sync = new object(); #endregion #region Ctor public EntityFrameworkRepositoryContext(DbContext efContext) { this.efContext = efContext; } #endregion #region Protected Methods protected override void Dispose(bool disposing) { if (disposing) { efContext.Dispose(); } base.Dispose(disposing); } #endregion #region IEntityFrameworkRepositoryContext Members public DbContext Context { get { return this.efContext; } } #endregion #region IRepositoryContext Members public override void RegisterNew(object obj) { this.efContext.Entry(obj).State = System.Data.Entity.EntityState.Added; Committed = false; } public override void RegisterModified(object obj) { this.efContext.Entry(obj).State = System.Data.Entity.EntityState.Modified; Committed = false; } public override void RegisterDeleted(object obj) { this.efContext.Entry(obj).State = System.Data.Entity.EntityState.Deleted; Committed = false; } #endregion #region IUnitOfWork Members public override bool DistributedTransactionSupported { get { return true; } } public override void Commit() { if (!Committed) { lock (sync) { efContext.SaveChanges(); } Committed = true; } } public override void Rollback() { Committed = false; } #endregion }
LCLFramework框架之Repository使用
public class Village : DomainEntity { public string Name { get; set; } } public interface IVillageRepository : IRepository<Village> { //倉庫擴展 List<Village> GetTest(); } [Serializable] [RepositoryFor(typeof(Village))] public class VillageRepository : EntityFrameworkRepository<Village>, IVillageRepository { private readonly IRepositoryContext context; public VillageRepository(IRepositoryContext context) : base(context) { this.context = context; } //倉庫擴展方法 public List<Village> GetTest() { return new List<Village>(); } }