最终大家能够确认领域对象该如何提供什么样表现格局,在运用进程中观望外界(应用层或其余世界对象)对它的必要

本章内容还在照管上传中,你能够等一体更新完结后再查阅也得以先预览已上传的剧情。。。。。。

本章内容还在重新整建上传中,你能够等一切更新完结后再查阅也能够先预览已上传的剧情。。。。。。

柒. 领域层的一声令下情势

七. 世界层的命令格局

  在上个章节里我们设计并编码了世界对象Permission,不过近来Permission并从未其余表现上的规划。那是因为我们不指出“凭空去制作行为”,而是在圈子对象第3个本子的代码达成之后就立即选择它。在使用进程中观望外界(应用层或别的世界对象)对它的供给,这个供给往往隐藏了一发揭发对象本质特征的提示。大家得以依据那一个提醒逐步发现出该对象越来越多的一坐一起特征,结合CA里有关的统筹原则,最后大家能够确认领域对象该怎么提供哪些表现格局。所以,我们不要在意领域对象在规划初期有点类似“贫血模型”,因为那不是它的末梢形象,那只是它成长的源点。那假诺经过一番尝试后,大家依旧尚未为目标增加其余方法吗?那种情景确实存在,某个对象存在的意思只是被其他对象引用,自身并从未提供别的表现格局,不过只要您的品种里多量充满着未有作为的世界对象,这就值得您警惕了,肯定是规划上出现了主要的不当。可是假若我们遵纪守法教程里的统一准备条件实施项目,基本上不会产出那种情景,所以也无须太过顾忌。

  在上个章节里大家设计并编码了世界对象Permission,然而近年来Permission并不曾任何表现上的统一盘算。那是因为我们不提议“凭空去制作行为”,而是在圈子对象第四个版本的代码落成之后就及时选用它。在运用进程中观看外界(应用层或任何世界对象)对它的须求,这几个需求往往隐藏了更进一步揭发对象本质特征的唤醒。大家得以依附那些提醒渐渐开掘出该目的越来越多的行为特征,结合CA里相关的宏图条件,最终大家得以明确领域对象该怎么提供哪些行为艺术。所以,咱们不要在意领域对象在陈设初期有点类似“贫血模型”,因为那不是它的最终形象,那只是它成长的起源。那假如通过一番品尝后,我们照旧不曾为目标增添其他措施吧?那种情形真正存在,有个别对象存在的意义只是被其他对象引用,自己并不曾提供其余表现艺术,但是1旦您的项目里大量满载着未有作为的领域对象,那就值得您警惕了,明确是布署上冒出了要害的谬误。可是倘使大家依照教程里的宏图标准实施项目,基本上不会油可是生那种情状,所以也不要太过忧虑。

  由此,大家一时半刻放下对世界模型的沉思,将思路转变来应用层,思量应用层对Permission有何供给。涉及到应用层我们又不得不缅石英手表现层对应用层会有何样必要,最后大家会发觉要钻探的主题素材其实是极限用户会有怎样需求。所以,大家着想第三个难点:用户怎么采用权限机制?这几个话题在前文也商量过,那里大家只用思念用户接纳权限的率先个必须操作是什么?

  因而,大家姑且放下对世界模型的思考,将思路调换成应用层,思量应用层对Permission有怎么样要求。涉及到应用层大家又不得不思索表现层对应用层会有啥须求,最后大家会意识要探究的主题素材其实是终点用户会有哪些须求。所以,大家着想第1个难题:用户怎么选择权限机制?那个话题在前文也钻探过,那里我们只用考虑用户选择权限的率先个必须操作是何许?

  当然是为品种成立权限描述了,大家须求定义整个项目提供了怎么样权力,唯有定义了权力新闻后系统技巧以此为参考识别登录者能够运用什么作用。由此,创设权限新闻是用户的首先个操作须要。可是大家要从使用者的角度对那几个要求点进一步核对:“系统管理员能够定义整个项目提供了什么样职能”。系统管理员指的是项目搭建好后,设置项目早先参数的人,那类人比普通用户特别领悟系统(往往是大家和好)。从UI分界面操作体验上来讲,提醒使用者“定义整个项目提供了什么功能”比“定义整个项目提供了怎么样权力”要更易于明白。

  当然是为品种成立权限描述了,大家要求定义整个项目提供了什么权力,唯有定义了权力消息后系统本事以此为参考识别登陆者能够运用什么作用。由此,制造权限音讯是用户的首先个操作须求。然则大家要从使用者的角度对这些须要点进一步校对:“系统管理员能够定义整个项目提供了怎么职能”。系统管理员指的是体系搭建好后,设置项目初叶参数的人,那类人比普通用户越发领会系统(往往是大家自个儿)。从UI分界面操作体验上来讲,提醒使用者“定义整个项目提供了什么样功用”比“定义整个项目提供了怎么着权力”要更便于领会。

  分析到那里,大家就精通不管UI分界面怎么描述,应用层都要提供“成立权限”的法力。所以大家以成立权限为示范讲述怎样树立世界命令。

  分析到那里,大家就精晓不管UI分界面怎么描述,应用层都要提供“创建权限”的功效。所以我们以创办权限为示范讲述如何树立世界命令。

  在CA的4层框架结构里,应用层由多个服务组合,
这几个服务不会一直操作领域对象,它们重假设通过调用子系统提供的一声令下来造成职务。相当于说,AccountSubsystem里除了定义领域模型的剧情外还会提供壹组命令给应用层使用,应用层不会一向动用世界模型,一切应用操作都以通过那个命令来下达给世界层去贯彻的。上面贴出创立权限的吩咐代码并作出说明:

  在CA的四层架构里,应用层由四个劳务组合,
这个劳务不会一贯操作领域对象,它们重假使通过调用子系统提供的指令来成功任务。也正是说,AccountSubsystem里除了定义领域模型的始末外还会提供一组命令给应用层使用,应用层不会平昔运用领域模型,一切应用操作都是通过这么些命令来下达给世界层去落到实处的。下边贴出创造权限的下令代码并作出表明:

using System;
using System.Linq;

using CodeArt;
using CodeArt.DomainDriven;

namespace AccountSubsystem
{
    public sealed class CreatePermission : Command<Permission>
    {
        private string _name;

        public string Description
        {
            get;
            set;
        }

        public string MarkedCode
        {
            get;
            set;
        }

        public CreatePermission(string name)
        {
            _name = name;
        }

        protected override Permission ExecuteProcedure()
        {
            Permission permission = new Permission(Guid.NewGuid())
            {
                Name = _name,
                MarkedCode = this.MarkedCode ?? string.Empty,
                Description = this.Description ?? string.Empty
            };

            var repository = Repository.Create<IPermissionRepository>();
            repository.Add(permission);

            return permission;
        }
    }
}
using System;
using System.Linq;

using CodeArt;
using CodeArt.DomainDriven;

namespace AccountSubsystem
{
    public sealed class CreatePermission : Command<Permission>
    {
        private string _name;

        public string Description
        {
            get;
            set;
        }

        public string MarkedCode
        {
            get;
            set;
        }

        public CreatePermission(string name)
        {
            _name = name;
        }

        protected override Permission ExecuteProcedure()
        {
            Permission permission = new Permission(Guid.NewGuid())
            {
                Name = _name,
                MarkedCode = this.MarkedCode ?? string.Empty,
                Description = this.Description ?? string.Empty
            };

            var repository = Repository.Create<IPermissionRepository>();
            repository.Add(permission);

            return permission;
        }
    }
}

  一)public sealed class
CreatePermission :
Command<Permission>,类型CreatePermission承继自命令的泛型版本Command<T>,泛型参数表示该命令需求重临类型为T的结果,那里代表的是施行CreatePermission命令后,必要再次来到八个Permission权限对象。Command<T>来自Code阿特.DomainDriven命名空间,由程序集CodeArt.DomainDriven提供。CA规定除了查询操作外全部命令对象都需求继续自Command或Command<T>。

  一)public sealed class
CreatePermission :
Command<Permission>,类型CreatePermission承袭自命令的泛型版本Command<T>,泛型参数表示该命令须求重临类型为T的结果,那里代表的是施行CreatePermission命令后,须要再次回到三个Permission权限对象。Command<T>来自CodeArt.DomainDriven命名空间,由程序集CodeArt.DomainDriven提供。CA规定除了查询操作外全部命令对象都急需持续自Command或Command<T>。

  2) private string _name;  私有成员
_name用于收纳外界传递的权能名称的参数,请留意,因为name是必填项,所以以构造函数参数的花样强制需求外界必须传递name。名字为啥必填?
那跟守旧支付里表单必填项尚未任何涉及,而是因为世界模型Permission的性质Name定义的原则性规则包含了不能为空的限量。

  2) private string _name;  私有成员
_name用于收纳外界传递的权杖名称的参数,请留心,因为name是必填项,所以以构造函数参数的花样强制须求外界必须传递name。名为何必填?
这跟守旧支付里表单必填项尚未任何涉及,而是因为世界模型Permission的性质Name定义的固定规则包涵了无法为空的限量。

  三)Description和MarekdCode被规划成为属性并且当众了GET和SET方法,表示外界得以为权力选取性填写描述和标志码。请留心那不是小圈子属性,那是命令为了接收参数而编写的.NET属性,事实上你可以为那五个属性随机命名(比如desp或mc,可是考虑可阅读性大家从未那样命名)。那五个属性之所以不必填也是出于Permission对应的习性规则导致的,不再复述。

  3)Description和MarekdCode被规划成为属性并且当众了GET和SET方法,表示外界得以为权力选用性填写描述和标记码。请留意那不是世界属性,这是命令为了接收参数而编写的.NET属性,事实上你可感到那四个性子随机命名(举例desp或mc,可是思索可阅读性我们尚无这么命名)。这三个个性之所以不必填也是出于Permission对应的习性规则导致的,不再复述。

  4)protected override Permission
ExecuteProcedure()
是派生类必须贯彻基类Command<Permission>的施行命令的办法。

  4)protected override Permission
ExecuteProcedure()
是派生类必须兑现基类Command<Permission>的施行命令的艺术。

  5)在实行形式中,第1个段落代码正是协会领域对象Permission。那里要注意的是性质赋值语句:马克edCode
= this.马克edCode ?? string.Empty;
该代码的乐趣是,假如调用方未有传递马克edCode参数(未有传递就为null),那么就选用string.Empty作为标志码构造对象。前文表明过,在CA里存有的小圈子对象及世界属性值都不可能为null,那里就展现了这点,至于原因前文有详尽表明不再复述。

  伍)在实践办法中,第伍个段落代码就是组织领域对象Permission。这里要小心的是性质赋值语句:马克edCode
= this.马克edCode ?? string.Empty;
该代码的情致是,假设调用方未有传递马克edCode参数(未有传递就为null),那么就利用string.Empty作为标志码构造对象。前文表达过,在CA里存有的圈子对象及世界属性值都无法为null,那里就体现了那点,至于原因前文有详实表达不再复述。

  陆)var repository =
Repository.Create<IPermissionRepository>();
那句代码很轻便驾驭:创设多个接口类型为IPermissionRepository的蕴藏实例,该接口提供了关于Permission对象的持久化操作。接口的概念和得以完结稍后有详细表达。

  陆)var repository =
Repository.Create<IPermissionRepository>();
那句代码很轻便通晓:成立一个接口类型为IPermissionRepository的贮存实例,该接口提供了关于Permission对象的持久化操作。接口的概念和兑现稍后有详细表达。

  7)repository.Add(permission);
该代码将permission对象参预到仓库储存里。此刻CreatePermission的干活任何完了,最后回来permission对象。

  柒)repository.Add(permission);
该代码将permission对象参与到仓库储存里。此刻CreatePermission的干活方方面面做到,最后回到permission对象。

  上边我们来看看IPermissionRepository仓储是何等定义和贯彻的。以下是接口定义代码:

  上面我们来看看IPermissionRepository仓库储存是哪些定义和贯彻的。以下是接口定义代码:

namespace AccountSubsystem
{
    public interface IPermissionRepository : IRepository<Permission>
    {
        /// <summary>
        /// 根据唯一标示精确查找权限对象
        /// </summary>
        /// <param name="markedCode"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        Permission FindByMarkedCode(string markedCode, QueryLevel level);

        /// <summary>
        /// 根据名称模糊查找权限翻页集合
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <returns></returns>
        Page<Permission> FindPageBy(string name, int pageIndex, int pageSize);

        /// <summary>
        /// 根据编号得到多个权限对象
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        IEnumerable<Permission> FindsBy(IEnumerable<Guid> ids);
    }
}
namespace AccountSubsystem
{
    public interface IPermissionRepository : IRepository<Permission>
    {
        /// <summary>
        /// 根据唯一标示精确查找权限对象
        /// </summary>
        /// <param name="markedCode"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        Permission FindByMarkedCode(string markedCode, QueryLevel level);

        /// <summary>
        /// 根据名称模糊查找权限翻页集合
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <returns></returns>
        Page<Permission> FindPageBy(string name, int pageIndex, int pageSize);

        /// <summary>
        /// 根据编号得到多个权限对象
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        IEnumerable<Permission> FindsBy(IEnumerable<Guid> ids);
    }
}

   IPermissionRepository的概念代码比较轻巧,需求专注的有三点内容:

   IPermissionRepository的定义代码相比轻易,须求小心的有三点内容:

  一)在CA里领域对象仓库储存接口的定义必须接二连三自IRepository<TRoot>,该接口代码如下:

  一)在CA里领域对象仓储接口的概念必须承接自IRepository<TRoot>,该接口代码如下:

namespace CodeArt.DomainDriven
{
    public interface IRepository
    {
        /// <summary>
        /// 根据编号查找对象
        /// </summary>
        /// <param name="id"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        IAggregateRoot Find(object id, QueryLevel level);
    }


    public interface IRepository<TRoot> : IRepository
        where TRoot : class, IAggregateRoot
    {
        /// <summary>
        /// 将对象添加到仓储
        /// </summary>
        /// <param name="obj"></param>
        void Add(TRoot obj);

        /// <summary>
        /// 修改对象在仓储中的信息
        /// </summary>
        /// <param name="obj"></param>
        void Update(TRoot obj);

        /// <summary>
        /// 从仓储中删除对象
        /// </summary>
        /// <param name="obj"></param>
        void Delete(TRoot obj);

        /// <summary>
        /// 根据编号查找对象
        /// </summary>
        /// <param name="id"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        new TRoot Find(object id, QueryLevel level);
    }
}
namespace CodeArt.DomainDriven
{
    public interface IRepository
    {
        /// <summary>
        /// 根据编号查找对象
        /// </summary>
        /// <param name="id"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        IAggregateRoot Find(object id, QueryLevel level);
    }


    public interface IRepository<TRoot> : IRepository
        where TRoot : class, IAggregateRoot
    {
        /// <summary>
        /// 将对象添加到仓储
        /// </summary>
        /// <param name="obj"></param>
        void Add(TRoot obj);

        /// <summary>
        /// 修改对象在仓储中的信息
        /// </summary>
        /// <param name="obj"></param>
        void Update(TRoot obj);

        /// <summary>
        /// 从仓储中删除对象
        /// </summary>
        /// <param name="obj"></param>
        void Delete(TRoot obj);

        /// <summary>
        /// 根据编号查找对象
        /// </summary>
        /// <param name="id"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        new TRoot Find(object id, QueryLevel level);
    }
}

   从以上代码可以看到,由于IPermissionRepository承继了IRepository<Permission>接口,所以IPermissionRepository默许就定义了对权力对象的Add、Update、Delete、Find的操作。也正是说你兑现IPermissionRepository接口就非得也兑现那多少个措施。不过在利用CA的时候那多少个艺术的落到实处已经由框架内置了,不须求您手动编码。后文在讲到如何编写仓库储存落成的时候会详述。
  贰)我们为IPermissionRepository接口定义了多少个查询艺术,那个点子毫无空穴来风,正如前文所言,对待仓库储存接口的定义我们要11分郑重,不要将其陷入类似存款和储蓄进度般的存在。上边介绍下那多少个法子以及有关的话题:
  Permission FindBy马克edCode(string markedCode, QueryLevel level);
依照标志码找到权限对象,标志码的定义前文有详实讲授那里不再复述,有此方法的定义很正常,仓库储存必须提供依附标志码找到权限对象的天职。

   从上述代码可以观望,由于IPermissionRepository承继了IRepository<Permission>接口,所以IPermissionRepository暗中同意就定义了对权力对象的Add、Update、Delete、Find的操作。也便是说你达成IPermissionRepository接口就亟须也兑现这多少个办法。可是在应用CA的时候那多少个点子的贯彻已经由框架内置了,不需求您手动编码。后文在讲到怎样编写仓库储存完成的时候会详述。
  2)我们为IPermissionRepository接口定义了多少个查询情势,这几个格局毫无空穴来风,正如前文所言,对待仓库储存接口的定义大家要足够郑重,不要将其陷入类似存款和储蓄进程般的存在。上边介绍下那多少个措施以及有关的话题:
  Permission FindBy马克edCode(string markedCode, QueryLevel level);
根据标志码找到权限对象,标记码的定义前文有详尽疏解那里不再复述,有此方法的定义很正规,仓库储存必须提供依赖标记码找到权限对象的职责。

  注意第二个参数QueryLevel是查询等级,查询等第是1种加载对象的格局,提供那么些艺术是能够让程序的政工场景顺遂的举办下去。到方今甘休CA的新颖版本中协理五种查询等第以适应区别景观下的须求,它们各自是:无锁、独占、hold独占、共享、镜像。在详细座谈查询等级那个话题在此之前,大家不得不介绍一下事业。

  注意第二个参数QueryLevel是查询等第,查询品级是一种加载对象的主意,提供这几个方法是力所能及让程序的作业场景顺遂的施行下去。到目前截止CA的风靡版本中帮助五种查询等级以适应区别景色下的必要,它们各自是:无锁、独占、hold独占、共享、镜像。在详细谈论查询品级这几个话题从前,大家只能介绍一下事务。

  所谓事务正是指你必须原子性的到位1件事,那件事依然成功做到大概完全失败。例如说,你向体育场地付费借阅1本书A,你付出体育场馆伍元钱,图书管理员收取费用后把书A从书架上收取来给您。那些借书的事务就完整的达成了。不过假若您付出了开销后,管理员去取书A的时候发掘书已被借走了,这时候管理员就将收受的钱退还给你。那么这几个借书的职业就总体的败诉了,之所以说是完全的败诉是因为钱归还给你了,你囊中里的钱在借书在此以前是50元,在借书失败现在依旧50元,而不是四五元。事务实行时期的气象在失利的时候都应该能保险回逆到实践职业在此以前的图景。大家写的程序完成某些业务场景也要满意那么些供给,不可能说本身把钱支付给您了,书却因为借给别人了而没给笔者,钱也没退给本人,那种场所下的事务正是不完整的,是谬误的。

  所谓事务就是指你不可能不原子性的成功一件事,那件事仍旧成功完毕或然完全失利。举例说,你向体育地方付费借阅壹本书A,你提交体育场地伍元钱,图书助理馆员收取金钱后把书A从书架上收取来给您。这一个借书的事务就全体的姣好了。可是若是您付出了花费后,管理员去取书A的时候开掘书已被借走了,那时候管理员就将吸纳的钱退还给你。那么这一个借书的职业就全体的波折了,之所以说是完全的败诉是因为钱归还给你了,你囊中里的钱在借书从前是50元,在借书退步之后依然50元,而不是肆五元。事务实施时期的事态在战败的时候都应有能担保回逆到施行工作从前的情况。大家写的程序达成某些业务场景也要满意这一个必要,不能够说自家把钱支付给你了,书却因为借给别人了而没给小编,钱也没退给本身,那种景色下的事务正是不完整的,是漏洞百出的。

  要力保工作能够壹体化的实施有很三种艺术,一点都轻松,数据库这块也提供了成熟的缓和方案。然则若是要和属性结合在1道思量,追求高产出,高响应等目标那程序的繁杂就会提升广大。也正因如此,CA提供了查询级其余支撑以便缓和我们在支付进程中因为业务的拍卖而消耗过多的肥力。我们照旧以借书为例子详细疏解下那多少个查询品级的特性和平运动用办法。

  要确定保障专门的工作能够全体的实施有很各个格局,一点都简单,数据库那块也提供了成熟的化解方案。但是借使要和性情结合在协同考虑,追求高产出,高响应等目的那程序的错综复杂就会增高广大。也正因如此,CA提供了查询级其他协助以便缓慢化解我们在开拓进程中因为作业的管理而消耗过多的生命力。大家依旧以借书为例子详细疏解下那多少个查询级其他特点和使用格局。

  在您借书以前须求在多姿多彩标书架上找到感兴趣的图书,那种状态下大家一般不会太重视数据的及时性。就好比你今后在看一篇新闻的评论和介绍,同目前间也有人正在发表新的商量,那时候你并不知道,系统也不会提醒您,不过当您刷新页面的时候冲突新闻就被刷新了,纵然你前边看的并不是风靡的褒贬可是也不会给你带来多大的熏陶,对系统数据的完整性更不会变成任何破坏。因而,大家在只是为着查看内容而不会变动事物状态的操作下,一般选拔无锁的款式加载对象,因为无锁的查询质量是最棒的。你可以试想一下,若是你取得书籍消息是用带锁的查询格局,那么在您试行那项职责的时候,别的的人要探望图书必须得等到您查看达成后,而且她们也都亟待3个个的排队查阅,那眼看会急剧下跌系统的实用性。在CA中无锁的询问品级是QueryLevel.None,表示以无锁的法子加载领域对象,在该措施下任何的线程依旧得以读取、锁定该领域对象。值得一提的是QueryLevel.None完全不会跟其余锁争持的,固然你用其它的询问品级锁定了对象,可是采用无锁的秘诀相同能够读取,那也是干什么称它为“无”的来由。

  在你借书以前要求在灿烂的书架上找到感兴趣的书本,那种景况下我们一般不会太讲究数据的及时性。就好比你将来在看一篇音信的评头品足,同目前间也有人正在发布新的评头品足,那时候你并不知道,系统也不会唤起您,不过当你刷新页面包车型地铁时候批评新闻就被刷新了,尽管您后面看的并不是新型的评价不过也不会给你带来多大的影响,对系统数据的完整性更不会促成其余破坏。由此,大家在只是为了查看内容而不会转移事物状态的操作下,一般接纳无锁的款型加载对象,因为无锁的询问品质是最佳的。你可以试想一下,就算你获取书籍音讯是用带锁的询问办法,那么在你实施那项职责的时候,其他的人要看到图书必须得等到您查看完结后,而且他们也都急需四个个的排队查阅,这明明会小幅下落系统的实用性。在CA中无锁的查询品级是QueryLevel.None,表示以无锁的主意加载领域对象,在该办法下其余的线程还是能够读取、锁定该领域对象。值得1提的是QueryLevel.None完全不会跟别的锁冲突的,纵然你用别的的查询等第锁定了对象,不过利用无锁的艺术同样可以读取,那也是为什么称它为“无”的来头。

  当您选中了图书A后要求以垄断(monopoly)的不二等秘书技将它一时半刻证明为和煦的书。之所以说权且是因为你还不曾向管理员付费,管理员也并未有确认把书借给你。可是壹旦您在向管理员办理手续的时候,其余的人也要向管理员借阅那本书,其余人就需求等待你办理完后本事掌握自身能否三番五次借阅图书A(因为有异常的大概率您未曾带充裕的钱导致支付退步进而无法借阅,那时候别的人依然有机会能够继续品尝借阅图书A的)。所以一旦您选中了图书A将在将其权且独占,倘诺外人在你此前已经初步操办图书A的借阅操作,那么您也要等待,直到旁人释放了图书A的调整权后,你技能去找管理员办理借阅操作,就算有相当大恐怕管理员会告知您图书A已经被借走了。在那种景况下咱们就供给用到QueryLevel.Single
独占锁,先以独占的诀窍加载图书A,然后进行借阅的办理流程,那时候即使有任何的线程也以垄断(monopoly)的措施加载图书A,那么他们将不断等待到您办理终止结束。所以独占锁的好处是能够让日前线程非凡安全的操作某一个世界对象(注意,笔者说的是某叁个而不是多个领域对象,后文少禽有分解),因为目前线程不会被别的线程干扰操作(比方说有三个以致10多私有同时向管理员借阅图书那就乱套了)。独占锁的症结正是假设当前借阅图书A的人居多,那么她们只能排队等待,下落了系统的吞吐量。

  当您选中了图书A后须要以垄断(monopoly)的章程将它临时申明为本身的书。之所以说暂且是因为你还尚无向管理员付费,管理员也尚无确认把书借给你。可是即使你在向管理员办理手续的时候,别的的人也要向管理员借阅那本书,其余人就须要静观其变你办理完后技术驾驭自个儿能否持续借阅图书A(因为有比非常大也许您未有带丰硕的钱导致支付战败进而不能够借阅,那时候别的人仍旧有机遇能够一连品尝借阅图书A的)。所以只要您选中了图书A就要将其一时半刻独占,倘若外人在你在此之前曾经起来操办图书A的借阅操作,那么您也要等待,直到别人释放了图书A的调整权后,你才能去找管理员办理借阅操作,尽管有异常的大大概管理员会告知您图书A已经被借走了。在那种场地下大家就供给用到QueryLevel.Single
独占锁,先以独占的办法加载图书A,然后实行借阅的操办流程,那时候倘诺有任何的线程也以垄断(monopoly)的主意加载图书A,那么他们将不断等待到您办理完结结束。所以独占锁的便宜是能够让日前线程相当安全的操作某叁个领域对象(注意,笔者说的是某一个而不是多个领域对象,后文少禽有表达),因为脚下线程不会被其余线程搅扰操作(比如说有七个乃至拾多私家同时向管理员借阅图书那就乱套了)。独占锁的症结正是假设当前借阅图书A的人不少,那么她们只能排队等候,下跌了系统的吞吐量。

  QueryLevel.Single是锁定仓库储存中已存在的目标,那要是大家想锁定三个要么几个不设有的对象啊?借使在书籍馆理同样的书本(书名一样)只可以有1本仓库储存,当图书助理馆员在为新书上架的时候就要剖断书籍是还是不是已存在书架上,如若不设有才会议及展览开上架操作。教室一点都不小,有多位管理员同时在为新书上架,那时候大家在上架图书A以前就要把“图书A的空缺”锁定,其余的管理员不可能访问该空缺,直到大家做到上架操作释它的调节权结束。QueryLevel.HoldSingle就是用于这类场景下的查询品级,常用于新添操作验证目的的合法性。它能够把仓储中不存在的靶子给锁住,只要该对象满意你钦定的询问条件即可。

  QueryLevel.Single是锁定仓库储存中已存在的目的,那若是大家想锁定多少个要么八个不设有的对象呢?假若在书籍馆理同样的书本(书名同样)只好有一本仓库储存,当图书管理员在为新书上架的时候将在决断书籍是或不是已存在书架上,假设不设有才会开始展览上架操作。教室非常大,有多位管理员同时在为新书上架,那时候大家在上架图书A在此以前就要把“图书A的空缺”锁定,其余的总指挥不能够访问该空缺,直到我们做到上架操作释它的调节权结束。QueryLevel.HoldSingle正是用于那类场景下的询问等第,常用来新扩大操作验证目标的合法性。它能够把囤积中不设有的靶子给锁住,只要该目的知足你钦赐的查询条件就可以。

  QueryLevel.Share是共享的查询等第,它的定义比较简单:与QueryLevel.Single、QueryLevel.HoldSingle互斥,但是与QueryLevel.Share共享查询。也正是说,当自个儿在使用QueryLevel.Share查询有些对象的时候,你纵然用QueryLevel.Single或QueryLevel.HoldSingle查询该目的,这就得拭目以俟自身询问完结后你本领博得它的调整权。一样的,假设是您先用QueryLevel.Single或QueryLevel.HoldSingle查询对象,那么自个儿也要等待你操作截止后才干获取该目的的调控权。其余,若是你和本身都以用的QueryLevel.Share查询等级,那么大家得以同暂时间共同访问该对象。QueryLevel.Share常用于能够同步读取不过无法在读取的时候修改或删除对象的意况。

  QueryLevel.Share是共享的查询等级,它的概念相比较简单:与QueryLevel.Single、QueryLevel.HoldSingle互斥,然则与QueryLevel.Share共享查询。也正是说,当自个儿在动用QueryLevel.Share查询有个别对象的时候,你只要用QueryLevel.Single或QueryLevel.HoldSingle查询该对象,那就得拭目以俟自个儿询问达成后您才能得到它的调节权。同样的,要是是你先用QueryLevel.Single或QueryLevel.HoldSingle查询对象,那么作者也要等待你操作结束后才具赢得该对象的调控权。其它,假诺您和本身都以用的QueryLevel.Share查询等级,那么大家能够同临时间共同访问该目的。QueryLevel.Share常用于能够一并读取不过无法在读取的时候修改或删除对象的场馆。

  在承继讨论最终一种查询等级“镜像”在此之前,我们先对QueryLevel.None、QueryLevel.Single、QueryLevel.HoldSingle、QueryLevel.Share那种种品级举办总计:

  在承袭探讨最终一种查询等级“镜像”在此之前,我们先对QueryLevel.None、QueryLevel.Single、QueryLevel.HoldSingle、QueryLevel.Share那多样品级进行计算:

    (一)除了镜像查询外,使用其他各个查询级所获取的靶子自然会被存放在在天地缓冲区中,那意味同二个对象正是有上万个用户同时做客它,该目的始终也只会有3个实例在内部存款和储蓄器中设有。那样节约了内部存款和储蓄器费用、收缩了装载领域对象的时日(直接从世界缓冲区中取对象根本不需求装载,对象只有在第一遍从数据库中拿走才会进行李装运载操作),非常的大的加强了系统品质。

    (一)除了镜像查询外,使用别的八种查询级所获得的靶子自然会被存放在在世界缓冲区中,这代表同三个对象便是有上万个用户同时做客它,该目的始终也只会有三个实例在内部存款和储蓄器中设有。这样节约了内部存款和储蓄器开支、裁减了装载领域对象的岁月(直接从世界缓冲区中取对象根本不须要装载,对象只有在第二回从数据库中赢得才会实施李装运载操作),相当的大的增加了系统质量。

    (2)QueryLevel.None能够与任何其余查询等第共存,尽管你选拔了QueryLevel.Single只怕QueryLevel.HoldSingle,作者壹旦使用QueryLevel.None还能访问你锁定的目的。该查询等级质量最优,可是不可能担保对象的事态是安枕而卧的,被读取的对象有十分大概率正在被别的线程修改。因而,QueryLevel.None能够满意只是为着查看数据而施行的询问职业,它能够提供最优的查询功效。技师在运用该查询品级时,一定不能够改动目标对象情状(只可以读属性和平运动作不会毁掉对象意况的方法)。

    (2)QueryLevel.None能够与其余其余查询等第共存,纵然你采取了QueryLevel.Single或许QueryLevel.HoldSingle,小编1旦使用QueryLevel.None依然得以访问你锁定的目的。该查询级别质量最优,然则无法担保对象的气象是安全的,被读取的对象有十分的大可能率正在被别的线程修改。由此,QueryLevel.None能够知足只是为着查看数据而施行的查询职业,它能够提供最优的询问作用。技士在选取该查询等级时,一定不能够改动目的对象意况(只好读属性和平运动行不会破坏对象情状的法子)。

    (三)QueryLevel.Single和QueryLevel.HoldSingle用于增添或改变对象意况的现象,QueryLevel.Single的性质高于QueryLevel.HoldSingle。该查询可以提供精美的使用遭遇让你改换一个聚合根极其成员的气象,别的的线程不能够搅扰你对该聚合根的其它操作(尽管QueryLevel.None照旧得以查询,但是我们已作约定该查询下是相对不能够改造对象的对象状态的)。当您把某部聚合根锁定了,那么该聚合根的积极分子也被直接锁定了(因为访问成员要因此聚合根,你以带锁的款式加载了聚合根,别的线程就无法再锁定该聚合根,不可能访问聚合根就无法访问其成员,所以锁聚合根等同于其成员也被锁定了)。在三个作业里,一定不要采取QueryLevel.Single或QueryLevel.HoldSingle查询五个或八个以上的聚合根,那样有不小希望会招致死锁。简单的讲,你借使要操作五个聚合根并将其立异提交到仓库储存,你不要选用QueryLevel.Single和QueryLevel.HoldSingle,因为它们有不小概率导致对象死锁。之具备说“有非常大希望”是因为产生死锁的原委不是那三个查询等级导致的,而是你写的工作代码不适当的选取它们会引起死锁。那八个查询品级无法对你保险百分百制止死锁,面对七个聚合根同时被改变的光景请使用镜像技能。

    (三)QueryLevel.Single和QueryLevel.HoldSingle用于充实或更动对象景况的场馆,QueryLevel.Single的属性高于QueryLevel.HoldSingle。该查询可以提供精美的选拔条件让您更动贰个聚合根极其成员的景观,别的的线程不能苦恼你对该聚合根的任何操作(尽管QueryLevel.None依然得以查询,可是我们已作约定该查询下是纯属不能更换对象的目的状态的)。当你把某部聚合根锁定了,那么该聚合根的成员也被直接锁定了(因为访问成员要透过聚合根,你以带锁的方式加载了聚合根,其他线程就不可能再锁定该聚合根,不能够访问聚合根就不能够访问其成员,所以锁聚合根等同于其成员也被锁定了)。在三个作业里,一定毫无选择QueryLevel.Single或QueryLevel.HoldSingle查询四个或多少个以上的聚合根,那样有非常的大希望会产生死锁。简单来说,你假诺要操作四个聚合根并将其履新提交到仓储,你不要使用QueryLevel.Single和QueryLevel.HoldSingle,因为它们有希望导致对象死锁。之富有说“有相当大可能率”是因为形成死锁的原故不是那七个查询等级导致的,而是你写的作业代码不适当的行使它们会挑起死锁。那八个查询品级不可能对您担保百分之百幸免死锁,面对多少个聚合根同时被退换的情状请使用镜像本事。

    (四)QueryLevel.Share共享查询的习性介于QueryLevel.None之后、QueryLevel.Single在此之前。假若你既想以高效用读取对象只是又不想该目的的情事会在询问时期被改造,那么你就能够动用该查询等级。事实上我们在实质上接纳中很少用到共享查询,单纯的读取操作大约都以用QueryLevel.None。

    (四)QueryLevel.Share共享查询的品质介于QueryLevel.None之后、QueryLevel.Single此前。借使您既想以高作用读取对象然则又不想该对象的情形会在查询时期被更改,那么您就足以采纳该查询等第。事实上大家在骨子里运用中很少用到共享查询,单纯的读取操作大概都以用QueryLevel.None。

  好了,今后大家规范商讨镜像查询(QueryLevel.Mirroring)。首先,该查询品级会以无锁的样式绕过世界缓冲区,从仓库储存中加载全新的世界对象。因而,使用它你不会跟别的查询有任何顶牛,因为兼具线程都以分别操作各自的领域对象。其次,由于它是无锁查询,所以在目标查询和一而再被利用的之间,事务也不会被真正的开启(QueryLevel.None也如出1辙,不会张开事务),不开启事务数据库的下压力就会缩减过多。然后,你也足以修改被询问的对象的意况(那点和QueryLevel.None不均等,大家约定使用None是不能够改改对象情状的),最后,当你提交八个世界对象的退换时工作才会被真正敞开,而且CA会帮你以①种安全种类的形式锁定目的,不会导致死锁现象。那样不但专业的提交时间被缩减到最低而且救助技士幸免了死锁,那是镜像查询最大的独到之处。当你须要在三个事务时期修改三个或一个以上的世界对象时请使用镜像查询的诀窍。

  好了,未来大家标准商讨镜像查询(QueryLevel.Mirroring)。首先,该查询品级会以无锁的款式绕过世界缓冲区,从仓库储存中加载全新的领域对象。由此,使用它你不会跟其余查询有其余冲突,因为具有线程都以独家操作各自的圈子对象。其次,由于它是无锁查询,所以在对象查询和持续被选拔的中间,事务也不会被真正的拉开(QueryLevel.None也一致,不会敞开事务),不开启事务数据库的压力就会降价扣过多。然后,你也足以修改被询问的对象的图景(这一点和QueryLevel.None差别等,我们约定使用None是不能够修改对象处境的),最后,当您付出八个世界对象的退换时职业才会被真正敞开,而且CA会帮您以一种安全系列的秘籍锁定指标,不会促成死锁现象。那样不但业务的交由时间被削减到低于而且救助程序员制止了死锁,那是镜像查询最大的长处。当您需求在三个专门的学问期间修改贰个或1个以上的领域对象时请使用镜像查询的方式。

   到最近停止CA三.0中提供了以上各样查询级以满足大很多市廛级应用。除了这些之外,大家还提供了世界事件机制将大事务划分为多少个小事务举行付出,该机制得以落成的效益是在乎乐观锁和悲观锁之间。QueryLevel.Single和QueryLevel.HoldSingle属于悲观锁,那种锁在作业推行期间会将有关财富都锁定,就算很安全不过系统吞吐量就非常低。QueryLevel.Mirroring属于乐观锁,当镜像对象在提交的时候CA会相比较对象的版本号是还是不是与积攒中著录的版本号一样,假使不雷同表示镜像对象已经过期了,过期了的目的是不能够交到到仓库储存的。由此,乐观锁固然不会锁定能源,然而当出现施行工作的时候会有壹方以致多方提交失利,那是乐观锁的毛病,不能够担保全部人都付出成功。领域事件的功力就是在于悲观锁和乐观锁之间,把大事务划分为两个小事务,各样小事务被单独推行并且付诸,多个小事务全体交付成功,那么大职业就提交成功了。假若小事情提交战败了就会回逆事件,对专门的学问实行人工的补充,关于该机制越多的争辨留待后续示例中详述。

   到近年来甘休CA三.0中提供了上述三种查询级以满意大许多公司级应用。除了那一个之外,我们还提供了世界事件机制将大事务划分为多少个小事务举行提交,该机制落成的功效是在乎乐观锁和悲观锁之间。QueryLevel.Single和QueryLevel.HoldSingle属于悲观锁,那种锁在职业实施时期会将相关财富都锁定,纵然很安全可是系统吞吐量就非常低。QueryLevel.Mirroring属于乐观锁,当镜像对象在付给的时候CA会比较对象的版本号是或不是与积攒中记录的版本号同样,如若不相同表示镜像对象已经晚点了,过期了的靶子是不能够交付到仓库储存的。由此,乐观锁即便不会锁定财富,可是当出现实施专门的学问的时候会有一方居然多方提交退步,那是乐观锁的毛病,不能够担保全体人都付出成功。领域事件的法力就是在于悲观锁和乐观锁之间,把大事务划分为多个小事务,种种小事务被单独实践并且付诸,八个小事务全部付给成功,那么大工作就付出成功了。即使小事情提交失利了就会回逆事件,对事情进行人工的互补,关于该机制更加多的斟酌留待后续示例中详述。

  Page<Permission> FindPageBy(string
name, int pageIndex, int pageSize);
该措施相比较轻松,能够依据钦赐的页码和页面大小获得权限对象的会集。那里供给展开斟酌的是“遵照页码、页面大小”来收获壹组世界对象的会合,那貌似是UI层分界面突显情势影响到了世界层的计划。领域层的计划不该依赖表现层的显示格局吗?是的,领域层内的成分(领域对象、仓库储存等)不应该只是为着提供某1种表现层的急需而做出统一企图。不过正如前文所述,分析表现层的UI体验能够扶助大家找到事物的本质特征,而仓库储存描述的是“怎样找到事物”的特点。因此,我们会意识“由于三个特大型系统里的权杖对象会众多,借使由二个列表全体展现出来,用户的来看体验会很差,所以大家须求以翻页的款式展现权限音讯”(当然,你也能够认为权限对象数量不多,大家不必要翻页,那么仓库储存只用提供查询列表集结的艺术即可,那几个依照实际必要来,那种供给自己就是东西的特色)。所以,大家认为仓库储存提供以翻页的款型找到三个权力对象的方法是相符事物本质特征的,并不是受制于某1种UI思考而做出的陈设。实际上该方式能够用于别的的UI表现,比方手提式有线电话机端拖拉分界面,每拖拉三回就一定于多加载壹页内容。

  Page<Permission> FindPageBy(string
name, int pageIndex, int pageSize);
该方式相比较轻便,能够根据钦命的页码和页面大小得到权限对象的群集。那里须要打开商量的是“依据页码、页面大小”来收获壹组世界对象的聚众,那相似是UI层分界面展现格局影响到了世界层的图谋。领域层的规划不应有借助表现层的呈现方式吧?是的,领域层内的要素(领域对象、仓库储存等)不应有只是为着提供某一种表现层的须求而做出统一盘算。不过正如前文所述,分析表现层的UI体验能够帮助大家找到事物的本质特征,而仓库储存描述的是“怎么着找到事物”的性子。由此,大家会发觉“由于3个巨型系统里的权柄对象会成千上万,假使由多个列表全体显示出来,用户的观察体验会很差,所以大家要求以翻页的款式表现权限信息”(当然,你也足以感到权限对象数量不多,大家不要求翻页,那么仓库储存只用提供查询列表集结的办法就能够,这一个依照实际要求来,那种必要自身就是东西的风味)。所以,大家以为仓库储存提供以翻页的款型找到八个权力对象的章程是顺应事物本质特征的,并不是囿于于某1种UI思索而做出的安插。实际上该办法能够用来其余的UI表现,举例手提式有线电话机端拖拉界面,每拖拉三回就约等于多加载壹页内容。

  IEnumerable<Permission>
FindsBy(IEnumerable<Guid> ids)
是积攒定义的尾声叁个艺术,实际上最初安排权限仓库储存接口时大家并从未思量到它。但是在承继的其实使用中大家开采须要提供这么三个询问接口:依照多个号码找到多少个权力对象,那样有利于权限对象与其他世界对象协同职业。

  IEnumerable<Permission>
FindsBy(IEnumerable<Guid> ids)
是积累定义的末梢3个情势,实际上最初陈设权限仓库储存接口时我们并未设想到它。可是在承继的实在应用中大家发掘须求提供那样三个查询接口:依照三个号码找到多少个权力对象,那样便于权限对象与别的领域对象协同专门的学问。

  IPermissionRepository接口定义的连带话题就到此甘休了,再度重申一点,一定不要为了采纳的便宜而随便追加仓储接口的措施,那样会将储存沦为类似存储进度般的存在,大家要用领域对象技巧来差距业务的扑朔迷离而选取进程化的格局是心有余而力不足变成那或多或少的。关于怎么样设计仓库储存接口咱们会在更扑朔迷离的例子里再执教更加深远的话题。

  IPermissionRepository接口定义的连带话题就到此截止了,再次强调一点,一定毫无为了利用的福利而随便追加仓库储存接口的方法,那样会将积累沦为类似存款和储蓄进度般的存在,大家要用领域对象才具来区别业务的繁杂而利用进度化的办法是心有余而力不足变成这点的。关于怎样设计仓库储存接口我们会在更扑朔迷离的例子里再疏解更深入的话题。

8.
实现IPermissionRepository仓储

8.
实现IPermissionRepository仓储

  终归到了落成仓库储存的时候了。请我们只顾,从等级次序结构的角度来讲,“仓库储存接口”处于世界模型层,“仓库储存接口的落实”处于基础设备层。你在领域模型层里设计了聚合根,同时也依照必要统一希图了该聚合根的储存接口,不过世界模型层并不关切仓库储存接口由什么人来完结,它只了然“笔者公布了二个接口,基础设备层一定会帮自个儿落成,所以小编得以放心的运用仓库储存接口来行事”。

  到头来到了完成仓储的时候了。请大家留意,从档案的次序结构的角度来讲,“仓库储存接口”处于世界模型层,“仓库储存接口的完毕”处于基础设备层。你在天地模型层里设计了聚合根,同时也根据须要规划了该聚合根的仓库储存接口,可是世界模型层并不珍视仓储接口由何人来完毕,它只晓得“作者宣布了2个接口,基础设备层一定会帮小编完毕,所以自身能够放心的采纳仓库储存接口来干活”。

  由于仓储的落到实四处于基础设备层,那代表你能够运用任性数据库或然其余存款和储蓄本领来营造仓库储存。那一点与天地模型层分歧,在圈子模型层大家渴求明确不要选用任何数据库才能,全体职业逻辑都需求借助领域成分(领域对象、仓库储存接口、领域事件等)来驱动。那么,为什么仓库储存的贯彻大家却足以选择数据库技艺吧?前文不是说过围绕数据库搞开拓会有二种弊端吗?那是因为古板的支出中,技术员不仅仅用数据仓库储存放各类数码,还会用大批量的仓库储存过程依然sql语句来处总管情逻辑,而数据库天生是用来囤积数据的,不可能分解职业上的复杂性。所以我们在存款和储蓄的贯彻中,用数据仓库储存放领域对象的数目只是仍然不会用它来管理别的事情逻辑,全数的业务管理都会放在领域模型层,这样纵然用了数据库手艺也不会拉动混乱。

  由于仓储的落成处于基础设备层,这表示你能够行使任意数据库可能其余存款和储蓄才干来塑造仓库储存。这点与天地模型层分化,在世界模型层大家渴求自然毫无选用其余数据库本领,全部专业逻辑都亟需借助领域成分(领域对象、仓库储存接口、领域事件等)来驱动。那么,为啥仓库储存的得以完结大家却得以选取数据库技巧吧?前文不是说过围绕数据库搞开拓会有三种害处吗?那是因为价值观的开销中,工程师不仅仅用数据仓库储存放种种数据,还会用多量的贮存进程照旧sql语句来拍卖工作逻辑,而数据库天生是用来囤积数据的,无法分解工作上的纷纷。所以大家在存款和储蓄的贯彻中,用数据库存放领域对象的多寡只是依旧不会用它来拍卖别的业务逻辑,全部的专门的职业管理都会放在领域模型层,那样即便用了数据库才能也不会推动混乱。

  下边大家先斟酌下什么兑现权力的积累,然后演示怎样将该仓库储存注入到程序中。

  上边大家先商讨下怎么贯彻权力的贮存,然后演示怎么着将该仓库储存注入到程序中。

using System;
using System.Collections.Generic;
using CodeArt.DomainDriven;

using CodeArt.Concurrent;
using CodeArt.DomainDriven.DataAccess;

namespace AccountSubsystem
{
    [SafeAccess]
    public class SqlPermissionRepository : SqlRepository<Permission>, IPermissionRepository
    {
        public Permission FindByName(string name, QueryLevel level)
        {
            return DataContext.Current.QuerySingle<Permission>("name=@name", (arg) =>
             {
                 arg.Add("name", name);
             }, level);
        }

        public Permission FindByMarkedCode(string markedCode, QueryLevel level)
        {
            return DataContext.Current.QuerySingle<Permission>("markedCode=@markedCode", (arg) =>
            {
                arg.Add("markedCode", markedCode);
            }, level);
        }

        public Page<Permission> FindPageBy(string name, int pageIndex, int pageSize)
        {
            return DataContext.Current.Query<Permission>("name like %@name%", pageIndex, pageSize, (arg) =>
            {
                arg.Add("name", name);
            });
        }

        public IEnumerable<Permission> FindsBy(IEnumerable<Guid> ids)
        {
            return DataContext.Current.Query<Permission>("id in @ids", (arg) =>
            {
                arg.Add("ids", ids);
            }, QueryLevel.None);
        }

        public static readonly SqlPermissionRepository Instance = new SqlPermissionRepository();

    }
}
using System;
using System.Collections.Generic;
using CodeArt.DomainDriven;

using CodeArt.Concurrent;
using CodeArt.DomainDriven.DataAccess;

namespace AccountSubsystem
{
    [SafeAccess]
    public class SqlPermissionRepository : SqlRepository<Permission>, IPermissionRepository
    {
        public Permission FindByName(string name, QueryLevel level)
        {
            return DataContext.Current.QuerySingle<Permission>("name=@name", (arg) =>
             {
                 arg.Add("name", name);
             }, level);
        }

        public Permission FindByMarkedCode(string markedCode, QueryLevel level)
        {
            return DataContext.Current.QuerySingle<Permission>("markedCode=@markedCode", (arg) =>
            {
                arg.Add("markedCode", markedCode);
            }, level);
        }

        public Page<Permission> FindPageBy(string name, int pageIndex, int pageSize)
        {
            return DataContext.Current.Query<Permission>("name like %@name%", pageIndex, pageSize, (arg) =>
            {
                arg.Add("name", name);
            });
        }

        public IEnumerable<Permission> FindsBy(IEnumerable<Guid> ids)
        {
            return DataContext.Current.Query<Permission>("id in @ids", (arg) =>
            {
                arg.Add("ids", ids);
            }, QueryLevel.None);
        }

        public static readonly SqlPermissionRepository Instance = new SqlPermissionRepository();

    }
}

   以上是IPermissionRepository的完成,我们能够看到真正成功存款和储蓄工作的是数码上下文DataContext.Current,由于该对象相比较复杂大家稍后开单独的章节疏解。方今大家只用领悟能够通过调用DataContext.Current.QueryXXX方法就可以成功目的的询问职业。至于CUD操作SqlRepository<T>这几个基类已经内部变成了有关专门的学业,程序猿不必再去落到实处。上边大家以DataContext.Current.Query为例解说怎样查询聚合根对象。

   以上是IPermissionRepository的兑现,大家能够见见真正产生存款和储蓄工作的是数据上下文DataContext.Current,由于该目标相比复杂大家稍后开单独的章节疏解。方今我们只用通晓能够经过调用DataContext.Current.QueryXXX方法就足以变成目的的查询工作。至于CUD操作SqlRepository<T>那几个基类已经内部产生了有关工作,程序员不必再去贯彻。下边我们以DataContext.Current.Query为例解说怎么样询问聚合根对象。

   IEnumerable<T> Query<T>(this IDataContext dataContext,
string expression, Action<DynamicData> fillArg, QueryLevel level)
where T : class, IAggregateRoot

   IEnumerable<T> Query<T>(this IDataContext dataContext,
string expression, Action<DynamicData> fillArg, QueryLevel level)
where T : class, IAggregateRoot

  Query是泛型方法,泛型参数是急需查询的聚合根的体系,DataContext.Current.Query<Permission>表示的正是咱们供给查询八个Permission对象。参数expression是目标表达式,大家能够用接近sql的语法编写对象表明式

  Query是泛型方法,泛型参数是亟需查询的聚合根的体系,DataContext.Current.Query<Permission>表示的正是大家须求查询多个Permission对象。参数expression是目标表达式,我们得以用类似sql的语法编写对象表达式

实质上对不起,近日干活多少忙,更新速度会缓慢,请见谅。。。。。。

实则对不起,近日专业多少忙,更新速度会减缓,请见谅。。。。。。