zoukankan      html  css  js  c++  java
  • 基于DDD的.NET开发框架

    返回ABP系列

    ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称。

    ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它旨在成为一个通用的WEB应用程序框架和项目模板。

    ABP的官方网站:http://www.aspnetboilerplate.com

    ABP官方文档:http://www.aspnetboilerplate.com/Pages/Documents

    Github上的开源项目:https://github.com/aspnetboilerplate

    一、基本概念

    实体是DDD(领域驱动设计)的核心概念之一。Eirc Evans是这样描述的实体的:“它根本上不是通过属性定义的,而是通过一系列连续性和标识定义的”。因此,实体都有Id属性并且都存储到数据库中。一个实体一般会映射到数据库的一张表。

    1、实体类

    在ABP中,实体派生自Entity类,例如:

        public class Person : Entity
        {
            public virtual string Name { get; set; }
    
            public virtual DateTime CreationTime { get; set; }
    
            public Person()
            {
                CreationTime = DateTime.Now;
            }
        }

    上面定义了一个Person实体类,而且在Entity类中定义了一个Id属性,它是该Entity类的主键。因此,所有实体的主键名都是相同的,都是Id。

    主键Id的类型是可以改变的,默认是int(int32)的。如果你想将Id定义为其他类型,可以像下面那样显示声明:

        public class Person : Entity<long>
        {
            public virtual string Name { get; set; }
    
            public virtual DateTime CreationTime { get; set; }
    
            public Person()
            {
                CreationTime = DateTime.Now;
            }
        }

    主键Id也可以设置为string,Guid或其他类型的。

    Entity类重写了等号运算符(==),可以轻松地检查两个实体是否相同了(实体的Id相同则认为它们相同)。它也定义了IsTransient方法来检测它是否有Id。

    2、接口约定

    在很多应用程序中,很多实体具有像CreationTime的属性(数据库表也有该字段)用来指示该实体是什么时候被创建的。APB提供了一些有用的接口来实现这些类似的功能。也就是说,为这些实现了这些接口的实体,提供了一个通用的编码方式(通俗的说只要实现指定的接口就能实现指定的功能)。

    1)、审计

    实体类实现 IHasCreationTime 接口就可以具有CreationTime的属性。当该实体被插入到数据库时, ABP会自动设置该属性的值为当前时间。

    public interface IHasCreationTime
    {
        DateTime CreationTime { get; set; }
    }

    Person类可以通过实现IHasCreationTime接口来重写,如下:

    public class Person : Entity<long>, IHasCreationTime
    {
        public virtual string Name { get; set; }
    
        public virtual DateTime CreationTime { get; set; }
    
        public Person()
        {
            CreationTime = DateTime.Now;
        }
    }

    ICreationAudited通过增加了CreatorUserId扩展了IHasCreationTime:

    public interface ICreationAudited : IHasCreationTime
    {
        long? CreatorUserId { get; set; }
    }

    当保存一个新的实体时,ABP会自动地将当前的用户Id设置为CreatorUserId。

    你也可以通过从CreationAuditedEntity类派生实体,从而轻易地实现ICreationAudited。

    对于修改也有相似的接口:

    public interface IModificationAudited
    {
        DateTime? LastModificationTime { get; set; }
    
        long? LastModifierUserId { get; set; }
    }

    作为一个快捷方式,你可以从AuditedEntity类派生,而不需要直接实现IAudited。AuditedEntity类对于不同类型的Id属性也有泛型的版本。

    2)、软删除

    软删除是一个通用的模式被用来标记一个已经被删除的实体,而不是实际从数据库中删除记录。例如:你可能不想从数据库中硬删除一条用户记录,因为它被许多其它的表所关联。为了实现软删除的目的我们可以实现该接口 ISoftDelete:

    public interface ISoftDelete{
        bool IsDeleted { get; set; }
    }

    ABP实现了开箱即用的软删除模式。当一个软删除实体被删除后,ABP检测到之后,会阻止删除,将IsDeleted设置为true并更新数据库中的实体。而且,它会自动地过滤数据库中软删除的实体,不会检索(select)它们。

    如果你用了软删除,你有可能也想实现这个功能,就是记录谁删除了这个实体。要实现该功能你可以实现IDeletionAudited 接口,请看下面示例:

    public interface IDeletionAudited : ISoftDelete
    {
        long? DeleterUserId { get; set; }
        DateTime? DeletionTime { get; set; }
    }

    IDeletionAudited扩展了ISoftDelete,当删除一个实体时,ABP会自动设置这些属性。

    如果你想为一个实体实现所有的审计接口(创建,修改和删除),那么可以直接实现IFullAudited,因为它继承了所有的这些接口:

    public interface IFullAudited : IAudited, IDeletionAudited
    {
            
    }
    

    作为一个快捷方式,你可以直接从FullAuditedEntity 类派生你的实体类,因为该类已经实现了IFullAudited接口。

    注意:所有的审计接口和类都有一个定义导航属性到User实体的泛型版本(比如ICreationAudited和FullAuditedEntity<tprimarykey,tuser>)。

    3)、激活/未激活

    一些实体需要标记为激活的或未激活的。这样,你就可以根据实体的激活或者未激活状态来采取行动。你可以实现IPassivable接口来达到目的。该接口定义了IsActive属性。

    如果实体在第一次创建时是激活的,那么你可以在构造函数中将IsActive设置为true。

    这与软删除(IsDeleted)是不同的。如果一个实体是软删除的,那么它就不会从数据库中检索到了(ABP默认会阻止),但是,对于激活或者未激活的实体,控制获取实体完全取决于你。

    2、IEntity接口

    实际上,Entity类实现了IEntity接口(且Entity实现了IEntity)。如果不想从Entity类中派生,那么可以直接实现这些接口。但是,除非你有一个好的原因不从Entity类派生,否则,不建议这么做。

    二、ABP源码分析

    代码:

    部分类图:

    IEntity<TPrimaryKey>: 封装了PrimaryKey:Id,这是一个泛型类型

    IEntity: 封装了PrimaryKey:Id,这是一个int类型

    Entity<TPrimaryKey> :支持主键是泛型类型的Entity

    Entity:支持主键是int类型的Entity

    IHasCreationTime: 封装了CreationTime

    ICreationAudited: 封装了CreatorUserId,这个是long类型

    CreationAuditedEntity<TPrimaryKey> : 支持主键是泛型类型的Entity,并且封装了CreationTime 和 CreatorUserId

    CreationAuditedEntity: 只支持主键是int类型的Entity,并且封装了CreationTime 和 CreatorUserId

    ICreationAudited<TUser> :封装了泛型类型的creator

    CreationAuditedEntity<TPrimaryKey, TUser> :  支持主键是泛型类型,并且封装了泛型类型的creator的Entity

    ISoftDelete:封装了软删除的标志IsDeleted

    IHasDeletionTime:封装了DeletionTime

    IDeletionAudited:封装了DeleterUserId,这个是long类型

    IDeletionAudited: 封装了泛型类型的DeleterUser

    IHasModificationTime:封装了LastModificationTime

    IModificationAudited: 封装了LastModifierUserId,这个是long类型

    IModificationAudited<TUser> :  封装了泛型类型的LastModifierUser

    IAudited:从其父类接口那继承了Creation 和 Modification 的时间和UserID,这个是long类型

    AuditedEntity<TPrimaryKey> :支持主键是泛型类型的Entity,并且从其父类接口那继承了Creation 和 Modification 的时间和UserID,这个是long类型

    AuditedEntity: 与AuditedEntity<TPrimaryKey>的区别就是其只支持主键是int类型的Entity。

    AuditedEntity<TPrimaryKey, TUser> :与AuditedEntity<TPrimaryKey>的区别就是其支持泛型类型的LastModifierUser和CreatorUser。

    IAudited:从其父类接口那继承了Creation,Modification和delete 的时间和UserID,这个是long类型

    FullAuditedEntity<TPrimaryKey> :支持主键是泛型类型的Entity,并且从其父类接口那继承了Creation,Modification和delete 的时间和UserID,这个是long类型

    FullAuditedEntity:与FullAuditedEntity<TPrimaryKey>的区别就是其只支持主键是int类型的Entity

    FullAuditedEntity<TPrimaryKey, TUser> :与FullAuditedEntity<TPrimaryKey>的区别就是其支持泛型类型的LastModifierUser,CreatorUser 和 deleteuser。

  • 相关阅读:
    【剑指offer】3-数组中重复的数字
    自定义管道遇到问题解决方案
    vue的双向绑定示例
    子组件传递给父组件数据
    vue里的共享对象示例
    mysql里的explain介绍
    mysql索引
    修改MySQL字符集
    v-model修饰符示例
    vue下拉列表示例
  • 原文地址:https://www.cnblogs.com/yinrq/p/5524289.html
Copyright © 2011-2022 走看看