LCLFramework框架之Repository模式
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>(); } }