首页 > 代码库 > LCLFramework框架之Repository模式

LCLFramework框架之Repository模式

Respository模式在示例中的实际目的小结一下


  1. Repository模式是架构模式,在设计架构时,才有参考价值;
  2. Repository模式主要是封装数据查询和存储逻辑;
  3. Repository模式实际用途:更换、升级ORM 引擎,不影响业务逻辑;
  4. 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仓库,对于个人来使用已经足够了。

ard_thumb[1]

LCLFramework框架之Repository模式设计代码


clipboard[1]

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 = http://www.mamicode.com/!(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 = http://www.mamicode.com/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扩展


clipboard[2]

  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使用


    [Serializable]

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

        }

    }

LCLFramework框架之Repository模式