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
,往里面添加了 IRemoteService
、IApplicationService
、IUnitOfWOrkEnabled
三种接口类型。添加了三种类型之后,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; }
剩余的 IValidationEnabled
、IUnitOfWorkEnabled
、IAuditingEnabled
、ITransientDependency
接口类似于一个启用标识,只要类型继承了该接口,就会执行一些特殊的操作。
基类,注入大量基础设施,比如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); }