DDD模块

 context.Services.AddSingleton(typeof(IDataFilter<>), typeof(DataFilter<>));

 

模块的依赖模块

 [DependsOn(
        typeof(AbpAuditingModule),
        typeof(AbpDataModule),
        typeof(AbpEventBusModule),
        typeof(AbpGuidsModule),
        typeof(AbpMultiTenancyModule),
        typeof(AbpThreadingModule),
        typeof(AbpTimingModule),
        typeof(AbpUnitOfWorkModule),
        typeof(AbpObjectMappingModule)
        )]
    public class AbpDddDomainModule : AbpModule
    {

    }

 1、实体

    Defines an entity. It's primary key may not be "Id" or it may have a composite primary key.  

   object[] GetKeys();

  在 IEntity<TKey> 的默认实现 Entity<TKey> 中,不仅提供了标识定义,也重写了 Equals() 比较方法和 ==  != 操作符,用于区别不同实体

   1)聚合根

聚合就是一组相关对象的集合,他会有一个根对象(root),和它的一个边界(boundary)。对于聚合外部来说,只能够引用它的根对象,而在聚合内部的其他对象则可以相互引用。

该类型也继承自 Entity 类型,并且内部提供了一个并发令牌防止并发冲突。并且在其内部也提供了领域事件的快速增删方法,其他的与常规实体基本一致。通过领域事件,我们可以完成对事务的拆分。例如上述的例子当中,我们也可以为 Part 增加一个领域事件,当价格被更新时,PO 可以订阅这个事件,实现对应的采购项更新。

    [Serializable]
    public abstract class AggregateRoot<TKey> : Entity<TKey>, 
        IAggregateRoot<TKey>, 
        IGeneratesDomainEvents, 
        IHasExtraProperties,
        IHasConcurrencyStamp
    public interface IGeneratesDomainEvents
    {
        IEnumerable<object> GetLocalEvents();

        IEnumerable<object> GetDistributedEvents();

        void ClearLocalEvents();

        void ClearDistributedEvents();
    }

什么是审计属性呢?在 ABP vNext 内部将以下属性定义为审计属性:创建人创建时间修改人修改时间删除人删除时间软删除标记

2)AuditedAggregateRootWithUser<TUser> 携带User的class类  public virtual TUser Creator { get; set; }

Audited和FullAudit的区别:

audited包括Creation,Modification的相关信息,

而FullAudit除了audited信息,还包括了IsDeleted,DeleterId,DeletionTime等软删除信息

3)事件

  public class EntityEventData<TEntity> : IEventDataWithInheritableGenericArgument

 DomainEventEntry

2、仓储

IReadOnlyBasicRepository<TEntity> ;包括GetList(),GetCount()

IReadOnlyBasicRepository<TEntity, TKey>; 增加Gets an entity with given primary key

IBasicRepository<TEntity, TKey>;在IReadOnlyBasicRespository基础上增加Insert,Update,Delete

IRepository是在增加表达式树,并且包括IReadOnlyBasicRepository, IBasicRepository

public interface IRepository<TEntity, TKey> : IRepository<TEntity>, 
IReadOnlyRepository<TEntity, TKey>, IBasicRepository<TEntity, TKey> where TEntity : class, IEntity<TKey> { }

RepositoryBase比BasicRepositoryBase,增加IDataFilter,ICurrentTenant,IQueryable

    public abstract class RepositoryBase<TEntity> : BasicRepositoryBase<TEntity>, IRepository<TEntity>
        where TEntity : class, IEntity

 

AbpDataFilterOptions:设置每个类型的数据筛选状态是否启用

IDataFilter<TFilter>,在模块的ConfigureServices已注入Singleton模式,获取当前类型是否数据筛选状态,为了保证每一个类型可以得到值 ,首先来源AbpDataFilterOptions,若存在,克隆一个,若不存在则设置为true

DataFilter,IDataFilter自动注册Singleton到容器里,往容器取出IDataFilter<TFilter>进行Enable、Disable,若第一次增加到自身集合,方便下次操作

 

 

 

 

抽象方法RepositoryRegistrarBase,仓储的具体实现模块都实现了这个基类

实现有EfCoreRepositoryRegistrar;MemoryDbRepositoryRegistrar;MongoDbRepositoryRegistrar

仓储肯定会有多种实现的,例如 EF Core 的仓储实现肯定有自己的一套注册机制,

 

3、服务

IDomainService,DomainService

4、值对象 ValueObject

 

并且按照聚合的特性来说,其实聚合与聚合之间的通讯,主要是通过领域事件来实现的。

 

调用 ApiDescriptionModelOptions ,往里面添加了 IRemoteServiceIApplicationServiceIUnitOfWOrkEnabled 三种接口类型。添加了三种类型之后,ABP vNext 根据应用服务类创建控制器时,就会从这个 IgnoredInterfaces 判断哪些类型不被忽略 (即只会自动注册实现了三种接口的类型成为控制器)。

[DependsOn(
        typeof(AbpDddDomainModule),
        typeof(AbpSecurityModule),
        typeof(AbpObjectMappingModule),
        typeof(AbpValidationModule),
        typeof(AbpAuthorizationModule),
        typeof(AbpHttpAbstractionsModule),
        typeof(AbpSe、ttingsModule),
        typeof(AbpFeaturesModule)
        )]
    public class AbpDddApplicationModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            Configure<ApiDescriptionModelOptions>(options =>
            {
                options.IgnoredInterfaces.AddIfNotContains(typeof(IRemoteService));
                options.IgnoredInterfaces.AddIfNotContains(typeof(IApplicationService));
                options.IgnoredInterfaces.AddIfNotContains(typeof(IUnitOfWorkEnabled));
            });
        }
    }

1、Dtos

请求

ILimitedResultRequest  =》  int MaxResultCount { get; set; }

ISortedResultRequest=》string Sorting { get; set; }  比如 "Name";"Name DESC";"Name ASC, Age DESC"

IPagedResultRequest=》包括ILimitedResultRequest; int SkipCount { get; set; }  Skip count (beginning of the page).

IPagedAndSortedResultRequest=》 IPagedResultRequest, ISortedResultRequest

返回结果

TKey Id { get; set; }

IHasTotalCount =》  long TotalCount { get; set; } 

IListResult<T>  =》  IReadOnlyList<T> Items { get; set; }

IPagedResult<T> 包含 IListResult<T>, IHasTotalCount

实体

顺序:IEntityDto 》 CreationAuditedEntityDto 、CreationAuditedEntityWithUserDto》AuditedEntityDto、AuditedEntityWithUserDto<TUserDto>

=》FullAuditedEntityDto、FullAuditedEntityWithUserDto

2、Services

IRemoteService=》IApplicationService

所有应用服务都必须继承 IApplicationService,这个是肯定的,不然 ABP vNext 不会为我们生成需要的控制器。

 

public abstract class ApplicationService :
        IApplicationService,
        IAvoidDuplicateCrossCuttingConcerns,
        IValidationEnabled,
        IUnitOfWorkEnabled,
        IAuditingEnabled,
        ITransientDependency
    {

IAvoidDuplicateCrossCuttingConcerns 接口,它的主要作用是防止拦截器进行重复执行。

  public interface IAvoidDuplicateCrossCuttingConcerns
    {
        List<string> AppliedCrossCuttingConcerns { get; }
    }

例如调用购买这个 API 接口,首先会进入 ASP.NET Core 的审计日志 Filter,在 Filter 里面会将这个 API 接口归属的类型的 List 容器(接口里面定义的 List )里面写入一条记录,说明已经通过审计日志过滤器记录了。

写了审计日志之后,又会进入审计日志拦截器,这个时候拦截器就会对指定的类型进行判断,看是否已经被执行过了,因为这个类型的 List 容器有了之前过滤器的记录,所以不会重复执行。

        public static bool IsApplied([NotNull] object obj, [NotNull] string concern)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            if (concern == null)
            {
                throw new ArgumentNullException(nameof(concern));
            }

            return (obj as IAvoidDuplicateCrossCuttingConcerns)?.AppliedCrossCuttingConcerns.Contains(concern) ?? false;
        }

 剩余的 IValidationEnabledIUnitOfWorkEnabledIAuditingEnabledITransientDependency 接口类似于一个启用标识,只要类型继承了该接口,就会执行一些特殊的操作。

基类,注入大量基础设施,比如IUnitOfWorkManager、 IObjectMapper、IGuidGenerator、ILoggerFactory、ILogger、ICurrentTenant、ICurrentUser、ISettingProvider、IClock

IAuthorizationService、IFeatureChecker、IStringLocalizer

 public interface IAsyncCrudAppService<TEntityDto, in TKey, in TGetListInput, in TCreateInput, in TUpdateInput>
        : IApplicationService
        where TEntityDto : IEntityDto<TKey>
    {
        Task<TEntityDto> GetAsync(TKey id);

        Task<PagedResultDto<TEntityDto>> GetListAsync(TGetListInput input);

        Task<TEntityDto> CreateAsync(TCreateInput input);

        Task<TEntityDto> UpdateAsync(TKey id, TUpdateInput input);

        Task DeleteAsync(TKey id);
    }

 

posted on 2019-07-15 18:48  dollymi  阅读(511)  评论(0编辑  收藏  举报

导航