AbpDddDomainModule
AbpDddDomainSharedModule 供内部和外部使用的一些对象定义在这里, 定义接口,常量
此模块定义了 DDD 约定的一些概念,比如聚合,值对象,仓储等,并作业约定的注册(仓库接口)
聚合(根)、实体、值对象参考文章 https://www.cnblogs.com/netfocus/p/3307971.html
[DependsOn(
typeof(AbpAuditingModule),
typeof(AbpDataModule),
typeof(AbpEventBusModule),
typeof(AbpGuidsModule),
typeof(AbpTimingModule),
typeof(AbpObjectMappingModule),
typeof(AbpExceptionHandlingModule),
typeof(AbpSpecificationsModule),
typeof(AbpCachingModule),
typeof(AbpDddDomainSharedModule)
)]
public class AbpDddDomainModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
// 仓储模式默认注入
context.Services.AddConventionalRegistrar(
new AbpRepositoryConventionalRegistrar());
// 增加追踪器拦截器,好让 EntityChangeTracking,
//EnableEntityChangeTracking,DisableEntityChangeTracking
// 能起作用
context.Services.OnRegistered(
ChangeTrackingInterceptorRegistrar.RegisterIfNeeded);
}
}
DDD 概念定义
在 audit 模块定义了一些接口
public interface IHasCreationTime
{
DateTime CreationTime { get; }
}
public interface IMayHaveCreator<TCreator>
{
TCreator? Creator { get; }
}
public interface IMayHaveCreator
{
Guid? CreatorId { get; }
}
public interface ICreationAuditedObject : IHasCreationTime, IMayHaveCreator
{
}
public interface ICreationAuditedObject<TCreator> : ICreationAuditedObject,
IMayHaveCreator<TCreator>
{
}
public interface IMustHaveCreator<TCreator> : IMustHaveCreator
{
TCreator Creator { get; }
}
public interface IMustHaveCreator
{
Guid CreatorId { get; }
}
public interface IHasModificationTime
{
DateTime? LastModificationTime { get; }
}
public interface IModificationAuditedObject : IHasModificationTime
{
Guid? LastModifierId { get; }
}
public interface IModificationAuditedObject<TUser> : IModificationAuditedObject
{
TUser? LastModifier { get; }
}
public interface IAuditedObject : ICreationAuditedObject, IModificationAuditedObject
{
}
public interface IAuditedObject<TUser> : IAuditedObject, ICreationAuditedObject<TUser>,
IModificationAuditedObject<TUser>
{
}
public interface ISoftDelete
{
bool IsDeleted { get; }
}
public interface IHasDeletionTime : ISoftDelete
{
DateTime? DeletionTime { get; }
}
public interface IDeletionAuditedObject : IHasDeletionTime
{
Guid? DeleterId { get; }
}
public interface IDeletionAuditedObject<TUser> : IDeletionAuditedObject
{
TUser? Deleter { get; }
}
public interface IFullAuditedObject : IAuditedObject, IDeletionAuditedObject
{
}
public interface IFullAuditedObject<TUser> : IAuditedObject<TUser>, IFullAuditedObject,
IDeletionAuditedObject<TUser>
{
}
实体
public interface IEntity
{
object?[] GetKeys();
}
public interface IEntity<TKey> : IEntity
{
TKey Id { get; }
}
[Serializable]
public abstract class Entity : IEntity
{
protected Entity()
{
EntityHelper.TrySetTenantId(this);
}
public override string ToString()
{
return $"[ENTITY: {GetType().Name}] Keys = {GetKeys().JoinAsString(", ")}";
}
public abstract object?[] GetKeys();
public bool EntityEquals(IEntity other)
{
return EntityHelper.EntityEquals(this, other);
}
}
[Serializable]
public abstract class Entity<TKey> : Entity, IEntity<TKey>
{
public virtual TKey Id { get; protected set; } = default!;
protected Entity(){}
protected Entity(TKey id)
{
Id = id;
}
public override object?[] GetKeys()
{
return new object?[] { Id };
}
public override string ToString()
{
return $"[ENTITY: {GetType().Name}] Id = {Id}";
}
}
基于 audit 模块里定义接口有如下实体
- CreationAuditedEntity : Entity, ICreationAuditedObject
- AuditedEntity : CreationAuditedEntity, IAuditedObject
- FullAuditedEntity : AuditedEntity, IFullAuditedObject
- FullAuditedEntityWithUser
: FullAuditedEntity, IFullAuditedObject
领域事件
领域事件
//领域事件
public class DomainEventRecord
{
public object EventData { get; }
//事件顺序
public long EventOrder { get; }
public DomainEventRecord(object eventData, long eventOrder)
{
EventData = eventData;
EventOrder = eventOrder;
}
}
public interface IGeneratesDomainEvents
{
IEnumerable<DomainEventRecord> GetLocalEvents();
IEnumerable<DomainEventRecord> GetDistributedEvents();
void ClearLocalEvents();
void ClearDistributedEvents();
}
聚合根
public interface IAggregateRoot : IEntity{}
public interface IAggregateRoot<TKey> : IEntity<TKey>, IAggregateRoot{}
聚合根抽象
[Serializable]
public abstract class BasicAggregateRoot : Entity,
IAggregateRoot,
IGeneratesDomainEvents
{
private readonly ICollection<DomainEventRecord> _distributedEvents =
new Collection<DomainEventRecord>();
private readonly ICollection<DomainEventRecord> _localEvents =
new Collection<DomainEventRecord>();
public virtual IEnumerable<DomainEventRecord> GetLocalEvents()
{
return _localEvents;
}
public virtual IEnumerable<DomainEventRecord> GetDistributedEvents()
{
return _distributedEvents;
}
public virtual void ClearLocalEvents()
{
_localEvents.Clear();
}
public virtual void ClearDistributedEvents()
{
_distributedEvents.Clear();
}
protected virtual void AddLocalEvent(object eventData)
{
_localEvents.Add(new DomainEventRecord(eventData,
EventOrderGenerator.GetNext()));
}
protected virtual void AddDistributedEvent(object eventData)
{
_distributedEvents.Add(new DomainEventRecord(eventData,
EventOrderGenerator.GetNext()));
}
}
[Serializable]
public abstract class BasicAggregateRoot<TKey> : Entity<TKey>,
IAggregateRoot<TKey>,
IGeneratesDomainEvents
{
private readonly ICollection<DomainEventRecord> _distributedEvents =
new Collection<DomainEventRecord>();
private readonly ICollection<DomainEventRecord> _localEvents =
new Collection<DomainEventRecord>();
protected BasicAggregateRoot()
{
}
protected BasicAggregateRoot(TKey id)
: base(id)
{
}
public virtual IEnumerable<DomainEventRecord> GetLocalEvents()
{
return _localEvents;
}
public virtual IEnumerable<DomainEventRecord> GetDistributedEvents()
{
return _distributedEvents;
}
public virtual void ClearLocalEvents()
{
_localEvents.Clear();
}
public virtual void ClearDistributedEvents()
{
_distributedEvents.Clear();
}
protected virtual void AddLocalEvent(object eventData)
{
_localEvents.Add(new DomainEventRecord(eventData,
EventOrderGenerator.GetNext()));
}
protected virtual void AddDistributedEvent(object eventData)
{
_distributedEvents.Add(new DomainEventRecord(eventData,
EventOrderGenerator.GetNext()));
}
}
聚合根
[Serializable]
public abstract class AggregateRoot : BasicAggregateRoot,
IHasExtraProperties,
IHasConcurrencyStamp
{
public virtual ExtraPropertyDictionary ExtraProperties { get; protected set; }
[DisableAuditing]
public virtual string ConcurrencyStamp { get; set; }
protected AggregateRoot()
{
ConcurrencyStamp = Guid.NewGuid().ToString("N");
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
public virtual IEnumerable<ValidationResult> Validate(
ValidationContext validationContext)
{
return ExtensibleObjectValidator.GetValidationErrors(
this,
validationContext
);
}
}
[Serializable]
public abstract class AggregateRoot<TKey> : BasicAggregateRoot<TKey>,
IHasExtraProperties,
IHasConcurrencyStamp
{
public virtual ExtraPropertyDictionary ExtraProperties { get; protected set; }
[DisableAuditing]
public virtual string ConcurrencyStamp { get; set; }
protected AggregateRoot()
{
ConcurrencyStamp = Guid.NewGuid().ToString("N");
ExtraProperties = new ExtraPropertyDictionary();
//给扩展的属性设置默认值
this.SetDefaultsForExtraProperties();
}
protected AggregateRoot(TKey id)
: base(id)
{
ConcurrencyStamp = Guid.NewGuid().ToString("N");
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
public virtual IEnumerable<ValidationResult> Validate(
ValidationContext validationContext)
{
return ExtensibleObjectValidator.GetValidationErrors(
this,
validationContext
);
}
}
基于 audit 模块里定义接口有如下实体
- CreationAuditedAggregateRoot : AggregateRoot, ICreationAuditedObject
- AuditedAggregateRoot : CreationAuditedAggregateRoot, IAuditedObject
- FullAuditedAggregateRoot
: AuditedAggregateRoot , IFullAuditedObject -
FullAuditedAggregateRootWithUser
: FullAuditedAggregateRoot, IFullAuditedObject
值对象
public abstract class ValueObject
{
protected abstract IEnumerable<object> GetAtomicValues();
public bool ValueEquals(object obj)
{
if (obj == null || obj.GetType() != GetType())
{
return false;
}
var other = (ValueObject)obj;
var thisValues = GetAtomicValues().GetEnumerator();
var otherValues = other.GetAtomicValues().GetEnumerator();
var thisMoveNext = thisValues.MoveNext();
var otherMoveNext = otherValues.MoveNext();
while (thisMoveNext && otherMoveNext)
{
if (ReferenceEquals(thisValues.Current, null) ^
ReferenceEquals(otherValues.Current, null))
{
return false;
}
if (thisValues.Current != null &&
!thisValues.Current.Equals(otherValues.Current))
{
return false;
}
thisMoveNext = thisValues.MoveNext();
otherMoveNext = otherValues.MoveNext();
if (thisMoveNext != otherMoveNext)
{
return false;
}
}
return !thisMoveNext && !otherMoveNext;
}
}
领域服务
DDD 理论来说,只有领域当中某个重要的过程或者转换操作不是实体或值对象的自然职责的时候,就 应该添加一个独立的服务来承载这些操作
public interface IDomainService : ITransientDependency
{
}
// DomainService 类内的属性都是通懒加载进行的缓存,因为有可能一个服务的构造函数同时注入多个瞬死的领域服务,说以就有必在领域服务里缓存下这些服务
//这里不不好的是使用了属性注入
public abstract class DomainService : IDomainService
{
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!;
[Obsolete("Use LazyServiceProvider instead.")]
public IServiceProvider ServiceProvider { get; set; } = default!;
protected IClock Clock => LazyServiceProvider.LazyGetRequiredService<IClock>();
//装载默认的,如果有其他实现用其他没有用 SimpleGuidGenerator.Instance
protected IGuidGenerator GuidGenerator =>
LazyServiceProvider.LazyGetService<IGuidGenerator>(SimpleGuidGenerator.Instance);
protected ILoggerFactory LoggerFactory =>
LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
protected ICurrentTenant CurrentTenant =>
LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
protected IAsyncQueryableExecuter AsyncExecuter =>
LazyServiceProvider.LazyGetRequiredService<IAsyncQueryableExecuter>();
protected ILogger Logger =>
LazyServiceProvider.LazyGetService<ILogger>(provider => LoggerFactory?.
CreateLogger(GetType().FullName!) ?? NullLogger.Instance);
}
仓储
IEntityChangeTrackingProvider 更改 Tracking
public interface IEntityChangeTrackingProvider
{
bool? Enabled { get; }
IDisposable Change(bool? enabled);
}
public class EntityChangeTrackingProvider : IEntityChangeTrackingProvider,
ISingletonDependency
{
public bool? Enabled => _current.Value;
private readonly AsyncLocal<bool?> _current = new AsyncLocal<bool?>();
//达到改变只能是在 Change 调用的 scope 范围内,出了范围, Enabled 恢复的之前的的值
public IDisposable Change(bool? enabled)
{
var previousValue = Enabled;
_current.Value = enabled;
return new DisposeAction(() => _current.Value = previousValue);
}
}
仓储接口
public interface IRepository
{
bool? IsChangeTrackingEnabled { get; }
}
//只读 定义读方法
public interface IReadOnlyBasicRepository<TEntity> : IRepository
where TEntity : class, IEntity
{
Task<List<TEntity>> GetListAsync(bool includeDetails = false,
CancellationToken cancellationToken = default);
Task<long> GetCountAsync(CancellationToken cancellationToken = default);
Task<List<TEntity>> GetPagedListAsync(
int skipCount,
int maxResultCount,
string sorting,
bool includeDetails = false,
CancellationToken cancellationToken = default);
}
//增加 通过 id 获取 实体
public interface IReadOnlyBasicRepository<TEntity, TKey> :
IReadOnlyBasicRepository<TEntity>
where TEntity : class, IEntity<TKey>
{
[NotNull]
Task<TEntity> GetAsync(TKey id, bool includeDetails =
true, CancellationToken cancellationToken = default);
Task<TEntity?> FindAsync(TKey id, bool includeDetails =
true, CancellationToken cancellationToken = default);
}
//增加 insert update delete
public interface IBasicRepository<TEntity> : IReadOnlyBasicRepository<TEntity>
where TEntity : class, IEntity
{
[NotNull]
Task<TEntity> InsertAsync([NotNull] TEntity entity, bool autoSave =
false, CancellationToken cancellationToken = default);
Task InsertManyAsync([NotNull] IEnumerable<TEntity> entities, bool autoSave =
false, CancellationToken cancellationToken = default);
[NotNull]
Task<TEntity> UpdateAsync([NotNull] TEntity entity, bool autoSave =
false, CancellationToken cancellationToken = default);
Task UpdateManyAsync([NotNull] IEnumerable<TEntity> entities, bool autoSave =
false, CancellationToken cancellationToken = default);
Task DeleteAsync([NotNull] TEntity entity, bool autoSave =
false, CancellationToken cancellationToken = default);
Task DeleteManyAsync([NotNull] IEnumerable<TEntity> entities, bool autoSave =
false, CancellationToken cancellationToken = default);
}
//增加通过 Id 直接删除实体
public interface IBasicRepository<TEntity, TKey> : IBasicRepository<TEntity>,
IReadOnlyBasicRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
Task DeleteAsync(TKey id, bool autoSave =
false, CancellationToken cancellationToken = default); //TODO: Return true if deleted
Task DeleteManyAsync(
[NotNull] IEnumerable<TKey> ids, bool autoSave = false,
CancellationToken cancellationToken = default);
}
抽象实现 BasicRepositoryBase
public abstract class BasicRepositoryBase<TEntity> :
IBasicRepository<TEntity>,
IServiceProviderAccessor,
IUnitOfWorkEnabled
where TEntity : class, IEntity
{
//属性注入
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!;
//属性注入
public IServiceProvider ServiceProvider { get; set; } = default!;
// 通过 IDataFilter 获取所有此仓库可用的数据过滤器
public IDataFilter DataFilter =>
LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
public ICurrentTenant CurrentTenant =>
LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public IAsyncQueryableExecuter AsyncExecuter =>
LazyServiceProvider.LazyGetRequiredService<IAsyncQueryableExecuter>();
public IUnitOfWorkManager UnitOfWorkManager =>
LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
// 获取 CancellationToken,在 asp.net core 里 获取 http context 的全局取消 token
public ICancellationTokenProvider CancellationTokenProvider =>
LazyServiceProvider.LazyGetService<ICancellationTokenProvider>(
NullCancellationTokenProvider.Instance);
public ILoggerFactory? LoggerFactory =>
LazyServiceProvider.LazyGetService<ILoggerFactory>();
public ILogger Logger => LazyServiceProvider.LazyGetService<ILogger>(provider =>
LoggerFactory?.CreateLogger(GetType().FullName!) ?? NullLogger.Instance);
//
public IEntityChangeTrackingProvider EntityChangeTrackingProvider =>
LazyServiceProvider.LazyGetRequiredService<IEntityChangeTrackingProvider>();
public bool? IsChangeTrackingEnabled { get; protected set; }
protected BasicRepositoryBase()
{
}
public abstract Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false,
CancellationToken cancellationToken = default);
public virtual async Task InsertManyAsync(IEnumerable<TEntity> entities,
bool autoSave = false, CancellationToken cancellationToken = default)
{
foreach (var entity in entities)
{
await InsertAsync(entity, cancellationToken: cancellationToken);
}
if (autoSave)
{
await SaveChangesAsync(cancellationToken);
}
}
protected virtual Task SaveChangesAsync(CancellationToken cancellationToken)
{
//获取当前执行的工作单元
if (UnitOfWorkManager?.Current != null)
{
return UnitOfWorkManager.Current.SaveChangesAsync(cancellationToken);
}
return Task.CompletedTask;
}
public abstract Task<TEntity> UpdateAsync(TEntity entity, bool autoSave =
false, CancellationToken cancellationToken = default);
public virtual async Task UpdateManyAsync(IEnumerable<TEntity> entities,
bool autoSave = false, CancellationToken cancellationToken = default)
{
foreach (var entity in entities)
{
await UpdateAsync(entity, cancellationToken: cancellationToken);
}
if (autoSave)
{
await SaveChangesAsync(cancellationToken);
}
}
public abstract Task DeleteAsync(TEntity entity, bool autoSave = false,
CancellationToken cancellationToken = default);
public virtual async Task DeleteManyAsync(IEnumerable<TEntity> entities,
bool autoSave = false, CancellationToken cancellationToken = default)
{
foreach (var entity in entities)
{
await DeleteAsync(entity, cancellationToken: cancellationToken);
}
if (autoSave)
{
await SaveChangesAsync(cancellationToken);
}
}
public abstract Task<List<TEntity>> GetListAsync(bool includeDetails =
false, CancellationToken cancellationToken = default);
public abstract Task<List<TEntity>> GetListAsync(
Expression<Func<TEntity, bool>> predicate, bool includeDetails = false,
CancellationToken cancellationToken = default);
public abstract Task<long> GetCountAsync(
CancellationToken cancellationToken = default);
public abstract Task<List<TEntity>> GetPagedListAsync(int skipCount,
int maxResultCount, string sorting, bool includeDetails = false,
CancellationToken cancellationToken = default);
protected virtual CancellationToken GetCancellationToken(
CancellationToken preferredValue = default)
{
return CancellationTokenProvider.FallbackToProvider(preferredValue);
}
protected virtual bool ShouldTrackingEntityChange()
{
// If IsChangeTrackingEnabled is set, it has the highest priority.
//This generally means the repository is read-only.
if (IsChangeTrackingEnabled.HasValue)
{
return IsChangeTrackingEnabled.Value;
}
// If Interface/Class/Method has Enable/DisableEntityChangeTrackingAttribute,
// it has the second highest priority.
if (EntityChangeTrackingProvider.Enabled.HasValue)
{
return EntityChangeTrackingProvider.Enabled.Value;
}
// Default behavior is tracking entity change.
return true;
}
}
// 带 key 的
public abstract class BasicRepositoryBase<TEntity, TKey> : BasicRepositoryBase<TEntity>,
IBasicRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
public virtual async Task<TEntity> GetAsync(TKey id, bool includeDetails = true,
CancellationToken cancellationToken = default)
{
var entity = await FindAsync(id, includeDetails, cancellationToken);
if (entity == null)
{
throw new EntityNotFoundException(typeof(TEntity), id);
}
return entity;
}
public abstract Task<TEntity?> FindAsync(TKey id, bool includeDetails = true,
CancellationToken cancellationToken = default);
public virtual async Task DeleteAsync(TKey id, bool autoSave = false,
CancellationToken cancellationToken = default)
{
var entity = await FindAsync(id, cancellationToken: cancellationToken);
if (entity == null)
{
return;
}
await DeleteAsync(entity, autoSave, cancellationToken);
}
public async Task DeleteManyAsync([NotNull] IEnumerable<TKey> ids, bool
autoSave = false, CancellationToken cancellationToken = default)
{
foreach (var id in ids)
{
await DeleteAsync(id, cancellationToken: cancellationToken);
}
if (autoSave)
{
await SaveChangesAsync(cancellationToken);
}
}
}
RepositoryBase 抽象的最后出口
public abstract class RepositoryBase<TEntity> : BasicRepositoryBase<TEntity>,
IRepository<TEntity>, IUnitOfWorkManagerAccessor
where TEntity : class, IEntity
{
[Obsolete("Use WithDetailsAsync method.")]
public virtual IQueryable<TEntity> WithDetails()
{
return GetQueryable();
}
[Obsolete("Use WithDetailsAsync method.")]
public virtual IQueryable<TEntity>
WithDetails(params Expression<Func<TEntity, object>>[] propertySelectors)
{
return GetQueryable();
}
public virtual Task<IQueryable<TEntity>> WithDetailsAsync()
{
return GetQueryableAsync();
}
public virtual Task<IQueryable<TEntity>>
WithDetailsAsync(params Expression<Func<TEntity, object>>[] propertySelectors)
{
return GetQueryableAsync();
}
[Obsolete("Use GetQueryableAsync method.")]
protected abstract IQueryable<TEntity> GetQueryable();
public abstract Task<IQueryable<TEntity>> GetQueryableAsync();
public abstract Task<TEntity?> FindAsync(
Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default);
public async Task<TEntity> GetAsync(
Expression<Func<TEntity, bool>> predicate,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
var entity = await FindAsync(predicate, includeDetails, cancellationToken);
if (entity == null)
{
throw new EntityNotFoundException(typeof(TEntity));
}
return entity;
}
public abstract Task DeleteAsync(Expression<Func<TEntity, bool>> predicate,
bool autoSave = false, CancellationToken cancellationToken = default);
public abstract Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate,
CancellationToken cancellationToken = default);
protected virtual TQueryable ApplyDataFilters<TQueryable>(TQueryable query)
where TQueryable : IQueryable<TEntity>
{
return ApplyDataFilters<TQueryable, TEntity>(query);
}
//对查询应用数据过滤器 DataFilter 是单列,里面有所有的数据过滤器
protected virtual TQueryable ApplyDataFilters<TQueryable, TOtherEntity>(
TQueryable query)
where TQueryable : IQueryable<TOtherEntity>
{
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TOtherEntity)))
{
query = (TQueryable)query.WhereIf(DataFilter.IsEnabled<ISoftDelete>(),
e => ((ISoftDelete)e!).IsDeleted == false);
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TOtherEntity)))
{
var tenantId = CurrentTenant.Id;
query = (TQueryable)query.WhereIf(DataFilter.IsEnabled<IMultiTenant>(),
e => ((IMultiTenant)e!).TenantId == tenantId);
}
return query;
}
}
public abstract class RepositoryBase<TEntity, TKey> : RepositoryBase<TEntity>,
IRepository<TEntity, TKey>
where TEntity : class, IEntity<TKey>
{
public abstract Task<TEntity> GetAsync(TKey id, bool includeDetails = true,
CancellationToken cancellationToken = default);
public abstract Task<TEntity?> FindAsync(TKey id, bool includeDetails = true,
CancellationToken cancellationToken = default);
public virtual async Task DeleteAsync(TKey id, bool autoSave = false,
CancellationToken cancellationToken = default)
{
var entity = await FindAsync(id, cancellationToken: cancellationToken);
if (entity == null)
{
return;
}
await DeleteAsync(entity, autoSave, cancellationToken);
}
public async Task DeleteManyAsync([NotNull] IEnumerable<TKey> ids,
bool autoSave = false, CancellationToken cancellationToken = default)
{
foreach (var id in ids)
{
await DeleteAsync(id, cancellationToken: cancellationToken);
}
if (autoSave)
{
await SaveChangesAsync(cancellationToken);
}
}
}
EntityChangeTracking 特性
仓储是否使用追踪器,看是否有 EntityChangeTracking,EnableEntityChangeTracking,DisableEntityChangeTracking 这些特性
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public abstract class EntityChangeTrackingAttribute : Attribute
{
public virtual bool IsEnabled { get; set; }
public EntityChangeTrackingAttribute(bool isEnabled)
{
IsEnabled = isEnabled;
}
}
public class EnableEntityChangeTrackingAttribute : EntityChangeTrackingAttribute
{
public EnableEntityChangeTrackingAttribute()
: base(true)
{
}
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class DisableEntityChangeTrackingAttribute : EntityChangeTrackingAttribute
{
public DisableEntityChangeTrackingAttribute()
: base(false)
{
}
}
public class ChangeTrackingInterceptor : AbpInterceptor, ITransientDependency
{
private readonly IEntityChangeTrackingProvider _entityChangeTrackingProvider;
// IEntityChangeTrackingProvider 单例
public ChangeTrackingInterceptor(IEntityChangeTrackingProvider
entityChangeTrackingProvider)
{
_entityChangeTrackingProvider = entityChangeTrackingProvider;
}
public async override Task InterceptAsync(IAbpMethodInvocation invocation)
{
if (!ChangeTrackingHelper.IsEntityChangeTrackingMethod(invocation.Method,
out var changeTrackingAttribute))
{
await invocation.ProceedAsync();
return;
}
//在本方法上临时改变追踪器,方法执行完毕恢复追踪器的 默认值
using (_entityChangeTrackingProvider.Change(changeTrackingAttribute?.IsEnabled))
{
await invocation.ProceedAsync();
}
}
}
仓储注册
仓储注册 AddDefaultRepository 静态类,注册 Repository
public static class ServiceCollectionRepositoryExtensions
{
public static IServiceCollection AddDefaultRepository(
this IServiceCollection services,
Type entityType,
Type repositoryImplementationType,
bool replaceExisting = false)
{
//IReadOnlyBasicRepository<TEntity>
var readOnlyBasicRepositoryInterface = typeof(IReadOnlyBasicRepository<>).
MakeGenericType(entityType);
if (readOnlyBasicRepositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
//注入只读仓储 base
RegisterService(services, readOnlyBasicRepositoryInterface,
repositoryImplementationType, replaceExisting, true);
//IReadOnlyRepository<TEntity> 注入只读仓储
var readOnlyRepositoryInterface = typeof(IReadOnlyRepository<>).
MakeGenericType(entityType);
if (readOnlyRepositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
RegisterService(services, readOnlyRepositoryInterface,
repositoryImplementationType, replaceExisting, true);
}
//IBasicRepository<TEntity>
var basicRepositoryInterface = typeof(IBasicRepository<>).
MakeGenericType(entityType);
if (basicRepositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
RegisterService(services, basicRepositoryInterface,
repositoryImplementationType, replaceExisting);
//IRepository<TEntity>
var repositoryInterface = typeof(IRepository<>).MakeGenericType(entityType);
if (repositoryInterface.IsAssignableFrom(repositoryImplementationType))
{
RegisterService(services, repositoryInterface,
repositoryImplementationType, replaceExisting);
}
}
}
var primaryKeyType = EntityHelper.FindPrimaryKeyType(entityType);
//有唯一主键的实体注册仓储
if (primaryKeyType != null)
{
//IReadOnlyBasicRepository<TEntity, TKey>
var readOnlyBasicRepositoryInterfaceWithPk =
typeof(IReadOnlyBasicRepository<,>).MakeGenericType(entityType, primaryKeyType);
if (readOnlyBasicRepositoryInterfaceWithPk.
IsAssignableFrom(repositoryImplementationType))
{
RegisterService(services, readOnlyBasicRepositoryInterfaceWithPk,
repositoryImplementationType, replaceExisting, true);
//IReadOnlyRepository<TEntity, TKey>
var readOnlyRepositoryInterfaceWithPk = typeof(IReadOnlyRepository<,>).
MakeGenericType(entityType, primaryKeyType);
if (readOnlyRepositoryInterfaceWithPk.IsAssignableFrom(
repositoryImplementationType))
{
RegisterService(services, readOnlyRepositoryInterfaceWithPk,
repositoryImplementationType, replaceExisting, true);
}
//IBasicRepository<TEntity, TKey>
var basicRepositoryInterfaceWithPk = typeof(IBasicRepository<,>).
MakeGenericType(entityType, primaryKeyType);
if (basicRepositoryInterfaceWithPk.IsAssignableFrom(
repositoryImplementationType))
{
RegisterService(services, basicRepositoryInterfaceWithPk,
repositoryImplementationType, replaceExisting);
//IRepository<TEntity, TKey>
var repositoryInterfaceWithPk = typeof(IRepository<,>).
MakeGenericType(entityType, primaryKeyType);
if (repositoryInterfaceWithPk.IsAssignableFrom(
repositoryImplementationType))
{
RegisterService(services, repositoryInterfaceWithPk,
repositoryImplementationType, replaceExisting);
}
}
}
}
return services;
}
private static void RegisterService(
IServiceCollection services,
Type serviceType,
Type implementationType,
bool replaceExisting,
bool isReadOnlyRepository = false)
{
ServiceDescriptor descriptor;
//自读仓库没有必要进行 ChangeTracking
if (isReadOnlyRepository)
{
//注册只读仓库实现
services.TryAddTransient(implementationType);
//注册仓库接口及实现通过 ServiceDescriptor
descriptor = ServiceDescriptor.Transient(serviceType, provider =>
{
var repository = provider.GetRequiredService(implementationType);
ObjectHelper.TrySetProperty(repository.As<IRepository>(),
x => x.IsChangeTrackingEnabled, _ => false);
return repository;
});
}
else
{
descriptor = ServiceDescriptor.Transient(serviceType, implementationType);
}
if (replaceExisting)
{
services.Replace(descriptor);
}
else
{
services.TryAdd(descriptor);
}
}
}
RepositoryRegistrarBase
public abstract class RepositoryRegistrarBase<TOptions>
where TOptions : AbpCommonDbContextRegistrationOptions
{
public TOptions Options { get; }
protected RepositoryRegistrarBase(TOptions options)
{
Options = options;
}
public virtual void AddRepositories()
{
//可以自定义仓储注册
RegisterCustomRepositories();
//默认仓储注册
RegisterDefaultRepositories();
//默认指定仓储注册
RegisterSpecifiedDefaultRepositories();
}
//注册客户自定义仓库
protected virtual void RegisterCustomRepositories()
{
foreach (var customRepository in Options.CustomRepositories)
{
Options.Services.AddDefaultRepository(customRepository.Key,
customRepository.Value, replaceExisting: true);
}
}
//
protected virtual void RegisterDefaultRepositories()
{
if (!Options.RegisterDefaultRepositories)
{
return;
}
foreach (var entityType in GetEntityTypes(Options.OriginalDbContextType))
{
if (!ShouldRegisterDefaultRepositoryFor(entityType))
{
continue;
}
RegisterDefaultRepository(entityType);
}
}
protected virtual void RegisterSpecifiedDefaultRepositories()
{
foreach (var entityType in Options.SpecifiedDefaultRepositories)
{
if (!Options.CustomRepositories.ContainsKey(entityType))
{
RegisterDefaultRepository(entityType);
}
}
}
protected virtual void RegisterDefaultRepository(Type entityType)
{
Options.Services.AddDefaultRepository(
entityType,
GetDefaultRepositoryImplementationType(entityType)
);
}
protected virtual Type GetDefaultRepositoryImplementationType(Type entityType)
{
var primaryKeyType = EntityHelper.FindPrimaryKeyType(entityType);
if (primaryKeyType == null)
{
return Options.SpecifiedDefaultRepositoryTypes
? Options.DefaultRepositoryImplementationTypeWithoutKey!
.MakeGenericType(entityType)
: GetRepositoryType(Options.DefaultRepositoryDbContextType, entityType);
}
return Options.SpecifiedDefaultRepositoryTypes
? Options.DefaultRepositoryImplementationType!.MakeGenericType(
entityType, primaryKeyType)
: GetRepositoryType(Options.DefaultRepositoryDbContextType,
entityType, primaryKeyType);
}
protected virtual bool ShouldRegisterDefaultRepositoryFor(Type entityType)
{
if (!Options.RegisterDefaultRepositories)
{
return false;
}
if (Options.CustomRepositories.ContainsKey(entityType))
{
return false;
}
if (!Options.IncludeAllEntitiesForDefaultRepositories &&
!typeof(IAggregateRoot).IsAssignableFrom(entityType))
{
return false;
}
return true;
}
protected abstract IEnumerable<Type> GetEntityTypes(Type dbContextType);
protected abstract Type GetRepositoryType(
Type dbContextType, Type entityType);
protected abstract Type GetRepositoryType(
Type dbContextType, Type entityType, Type primaryKeyType);
}
👍🎉🎊