zoukankan      html  css  js  c++  java
  • DDD分层架构之仓储

    DDD分层架构之仓储(层超类型基础篇)

    前一篇介绍了仓储的基本概念,并谈了我对仓储的一些认识,本文将实现仓储的基本功能。

      仓储代表聚合在内存中的集合,所以仓储的接口需要模拟得像一个集合。仓储中有很多操作都是可以通用的,可以把这部分操作抽取到基类中。

      在Util.Domains项目中创建一个文件夹Repositories,这个文件夹用来放仓储相关的接口。在Repositories下创建一个仓储接口IRepository

      把仓储基接口放到Util.Domains,是因为仓储接口是在领域层定义的,这与传统三层架构的数据访问层接口的位置不同。

      仓储是基础设施层的组成部分,位于领域层的下方,按理来说,领域层应该依赖仓储,但这会导致领域层与具体数据访问组件耦合,降低了领域层的复用能力。为了让领域层更加纯净,可以应用依赖倒置原则(DIP。依赖倒置原则提到,高层模块不应该依赖低层模块,这里的高层模块就是领域层,低层模块是基础设施层的仓储。

      依赖倒置原则反转了两者的依赖关系,即仓储反过来依赖于领域层。为了让领域层可以访问到仓储提供的服务,需要抽取仓储接口,你可以把这些接口放到独立的程序集中,但这会增加不必要的开销。一种更好的方法是直接把低层接口放入使用它们的客户程序集中,这样可以简化设计,仅在必要时才分离出独立的接口程序集。依赖倒置原则不仅适用于仓储,对于任何可能导致高耦合的基础设施服务都适用,比如第三方外部接口,发邮件,发短信等。

      在Util.Datas.Ef项目中创建一个仓储实现类Repository

      仓储接口IRepository的代码如下。

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using Util.Datas;
    
    namespace Util.Domains.Repositories {
        /// <summary>
        /// 仓储
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <typeparam name="TKey">实体标识类型</typeparam>
        public interface IRepository<TEntity, in TKey> where TEntity : class, IAggregateRoot<TKey> {
            /// <summary>
            /// 添加实体
            /// </summary>
            /// <param name="entity">实体</param>
            void Add( TEntity entity );
            /// <summary>
            /// 添加实体
            /// </summary>
            /// <param name="entities">实体</param>
            void Add( IEnumerable<TEntity> entities );
            /// <summary>
            /// 修改实体
            /// </summary>
            /// <param name="entity">实体</param>
            void Update( TEntity entity );
            /// <summary>
            /// 移除实体
            /// </summary>
            /// <param name="id">实体标识</param>
            void Remove( TKey id );
            /// <summary>
            /// 移除实体
            /// </summary>
            /// <param name="entity">实体</param>
            void Remove( TEntity entity );
            /// <summary>
            /// 查找实体集合
            /// </summary>
            List<TEntity> FindAll();
            /// <summary>
            /// 查找实体集合
            /// </summary>
            IQueryable<TEntity> Find();
            /// <summary>
            /// 查找实体
            /// </summary>
            /// <param name="id">实体标识</param>
            TEntity Find( params object[] id );
            /// <summary>
            /// 查找实体列表
            /// </summary>
            /// <param name="ids">实体标识列表</param>
            List<TEntity> Find( IEnumerable<TKey> ids );
            /// <summary>
            /// 判断实体是否存在
            /// </summary>
            /// <param name="predicate">条件</param>
            bool Exists( Expression<Func<TEntity, bool>> predicate );
            /// <summary>
            /// 索引器查找,获取指定标识的实体
            /// </summary>
            /// <param name="id">实体标识</param>
            TEntity this[TKey id] { get; }
            /// <summary>
            /// 保存
            /// </summary>
            void Save();
            /// <summary>
            /// 获取工作单元
            /// </summary>
            IUnitOfWork GetUnitOfWork();
        }
    }
    复制代码
    复制代码
    using System;
    
    namespace Util.Domains.Repositories {
        /// <summary>
        /// 仓储
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        public interface IRepository<TEntity> : IRepository<TEntity, Guid> where TEntity : class, IAggregateRoot<Guid> {
        }
    }
    复制代码

      仓储实现类Repository的代码如下。

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Linq.Expressions;
    using Util.Domains;
    using Util.Domains.Repositories;
    
    namespace Util.Datas.Ef {
        /// <summary>
        /// 仓储
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        /// <typeparam name="TKey">实体标识类型</typeparam>
        public abstract class Repository<TEntity, TKey> : IRepository<TEntity, TKey> where TEntity : class, IAggregateRoot<TKey> {
            /// <summary>
            /// 初始化仓储
            /// </summary>
            /// <param name="unitOfWork">工作单元</param>
            protected Repository( IUnitOfWork unitOfWork ) {
                UnitOfWork = (EfUnitOfWork)unitOfWork;
            }
    
            /// <summary>
            /// Ef工作单元
            /// </summary>
            protected EfUnitOfWork UnitOfWork { get; private set; }
    
            /// <summary>
            /// 添加实体
            /// </summary>
            /// <param name="entity">实体</param>
            public void Add( TEntity entity ) {
                UnitOfWork.Set<TEntity>().Add( entity );
                UnitOfWork.CommitByStart();
            }
    
            /// <summary>
            /// 添加实体
            /// </summary>
            /// <param name="entities">实体</param>
            public void Add( IEnumerable<TEntity> entities ) {
                if ( entities == null )
                    return;
                UnitOfWork.Set<TEntity>().AddRange( entities );
                UnitOfWork.CommitByStart();
            }
    
            /// <summary>
            /// 修改实体
            /// </summary>
            /// <param name="entity">实体</param>
            public virtual void Update( TEntity entity ) {
                UnitOfWork.Entry( entity ).State = EntityState.Modified;
                UnitOfWork.CommitByStart();
            }
    
            /// <summary>
            /// 移除实体
            /// </summary>
            /// <param name="id">实体标识</param>
            public void Remove( TKey id ) {
                var entity = Find( id );
                if ( entity == null )
                    return;
                Remove( entity );
            }
    
            /// <summary>
            /// 移除实体
            /// </summary>
            /// <param name="entity">实体</param>
            public void Remove( TEntity entity ) {
                UnitOfWork.Set<TEntity>().Remove( entity );
                UnitOfWork.CommitByStart();
            }
    
            /// <summary>
            /// 查找实体集合
            /// </summary>
            public List<TEntity> FindAll() {
                return Find().ToList();
            }
    
            /// <summary>
            /// 查找实体
            /// </summary>
            public IQueryable<TEntity> Find() {
                return UnitOfWork.Set<TEntity>();
            }
    
            /// <summary>
            /// 查找实体
            /// </summary>
            /// <param name="id">实体标识</param>
            public TEntity Find( params object[] id ) {
                return UnitOfWork.Set<TEntity>().Find( id );
            }
    
            /// <summary>
            /// 查找实体列表
            /// </summary>
            /// <param name="ids">实体标识列表</param>
            public List<TEntity> Find( IEnumerable<TKey> ids ) {
                if ( ids == null )
                    return null;
                return Find().Where( t => ids.Contains( t.Id ) ).ToList();
            }
    
            /// <summary>
            /// 索引器查找,获取指定标识的实体
            /// </summary>
            /// <param name="id">实体标识</param>
            public TEntity this[TKey id] {
                get { return Find( id ); }
            }
    
            /// <summary>
            /// 判断实体是否存在
            /// </summary>
            /// <param name="predicate">条件</param>
            public bool Exists( Expression<Func<TEntity, bool>> predicate ) {
                return Find().Any( predicate );
            }
    
            /// <summary>
            /// 保存
            /// </summary>
            public void Save() {
                UnitOfWork.Commit();
            }
    
            /// <summary>
            /// 获取工作单元
            /// </summary>
            public IUnitOfWork GetUnitOfWork() {
                return UnitOfWork;
            }
        }
    }
    复制代码
    复制代码
    using System;
    using Util.Domains;
    
    namespace Util.Datas.Ef {
        /// <summary>
        /// 仓储
        /// </summary>
        /// <typeparam name="TEntity">实体类型</typeparam>
        public abstract class Repository<TEntity> : Repository<TEntity, Guid> where TEntity : class, IAggregateRoot<Guid> {
            /// <summary>
            /// 初始化仓储
            /// </summary>
            /// <param name="unitOfWork">工作单元</param>
            protected Repository( IUnitOfWork unitOfWork )
                : base( unitOfWork ) {
            }
        }
    }
    复制代码

      仓储是对聚合的操作,所以泛型接口声明IRepository<TEntity, in TKey> where TEntity : class, IAggregateRoot<TKey>对TEntity类型限定为聚合。

      在Repository实现类中,通过注入DbContext工作单元来完成所有的工作。IUnitOfWorkEfUnitOfWork是在应用程序框架实战十九:工作单元层超类型中定义的,EfUnitOfWork从DbContext派生,它有一个核心方法CommitByStart,用来告诉仓储,如果开启了工作单元就等待调用端通过Commit提交,否则立即提交。每个数据更新方法Add、Update、Remove都会调用CommitByStart方法。

      对于使用Entity Framework 进行Update修改操作有多种实现方式。在仓储基类中实现的Update方法比较通用,但我手工编写代码时一般会直接把聚合取出来,修改聚合属性,再提交工作单元。

      本文介绍了仓储通用操作的基本实现,后续文章我将介绍如何通过表达式树对查询扩展和封装。

      .Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。

      谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/

      下载地址:http://files.cnblogs.com/xiadao521/Util.2014.12.17.1.rar

    版权所有,转载请注明出处 何镇汐的技术博客
     
  • 相关阅读:
    luogu P1455 搭配购买
    浅谈筛素数
    luogu P1205 方块转换
    luogu P2241 统计方形
    luogu P1866 编号
    luogu P1042 乒乓球
    4.7清明考试(完蛋)
    LINUX 启动图形界面和查看运行级别
    密钥登录LINUX步骤
    服务命令只支持基本的LSB操作(启动、停止、重新启动、尝试重启、重新加载、强制重新加载、状态)。对于其他操作,请尝试使用systemctl。
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4170506.html
Copyright © 2011-2022 走看看