• 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);
        }
  • 相关阅读:
    LeetCode 230. Kth Smallest Element in a BST
    LeetCode 114. Flatten Binary Tree to Linked List
    LeetCode 222. Count Complete Tree Nodes
    LeetCode 129. Sum Root to Leaf Numbers
    LeetCode 113. Path Sum II
    LeetCode 257. Binary Tree Paths
    Java Convert String & Int
    Java Annotations
    LeetCode 236. Lowest Common Ancestor of a Binary Tree
    LeetCode 235. Lowest Common Ancestor of a Binary Search Tree
  • 原文地址:https://www.cnblogs.com/cloudsu/p/11190697.html
Copyright © 2020-2023  润新知