ef core
[DependsOn(typeof(AbpDddDomainModule))]
public class AbpEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbContextOptions>(options =>
{
options.PreConfigure(abpDbContextConfigurationContext =>
{
abpDbContextConfigurationContext.DbContextOptions
.ConfigureWarnings(warnings =>
{
warnings.Ignore(CoreEventId.LazyLoadOnDisposedContextWarning);
});
});
});
context.Services.TryAddTransient(typeof(IDbContextProvider<>),
typeof(UnitOfWorkDbContextProvider<>));
context.Services.AddTransient(typeof(IDbContextEventOutbox<>),
typeof(DbContextEventOutbox<>));
context.Services.AddTransient(typeof(IDbContextEventInbox<>),
typeof(DbContextEventInbox<>));
}
}
AbpEntityFrameworkCoreModule 用到了 扩展属性
扩展类配置选项
public class ObjectExtensionPropertyInfoEfCoreMappingOptions
{
[NotNull]
public ObjectExtensionPropertyInfo ExtensionProperty { get; }
[NotNull]
public ObjectExtensionInfo ObjectExtension => ExtensionProperty.ObjectExtension;
// EntityTypeBuilder PropertyBuilder 在 OnModelCreating 用到的俩个配置类
public Action<EntityTypeBuilder, PropertyBuilder>? EntityTypeAndPropertyBuildAction
{ get; set; }
public ObjectExtensionPropertyInfoEfCoreMappingOptions(
[NotNull] ObjectExtensionPropertyInfo extensionProperty)
{
ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty));
}
public ObjectExtensionPropertyInfoEfCoreMappingOptions(
[NotNull] ObjectExtensionPropertyInfo extensionProperty,
Action<EntityTypeBuilder, PropertyBuilder>? entityTypeAndPropertyBuildAction)
{
ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty));
EntityTypeAndPropertyBuildAction = entityTypeAndPropertyBuildAction;
}
}
扩展属性配置选项
public class ObjectExtensionPropertyInfoEfCoreMappingOptions
{
[NotNull]
public ObjectExtensionPropertyInfo ExtensionProperty { get; }
[NotNull]
public ObjectExtensionInfo ObjectExtension => ExtensionProperty.ObjectExtension;
public Action<EntityTypeBuilder, PropertyBuilder>?
EntityTypeAndPropertyBuildAction { get; set; }
public ObjectExtensionPropertyInfoEfCoreMappingOptions(
[NotNull] ObjectExtensionPropertyInfo extensionProperty)
{
ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty));
}
public ObjectExtensionPropertyInfoEfCoreMappingOptions(
[NotNull] ObjectExtensionPropertyInfo extensionProperty,
Action<EntityTypeBuilder, PropertyBuilder>? entityTypeAndPropertyBuildAction)
{
ExtensionProperty = Check.NotNull(extensionProperty, nameof(extensionProperty));
EntityTypeAndPropertyBuildAction = entityTypeAndPropertyBuildAction;
}
}
扩展对象
public static class EfCoreObjectExtensionInfoExtensions
{
public const string EfCoreDbContextConfigurationName = "EfCoreDbContextMapping";
public const string EfCoreEntityConfigurationName = "EfCoreEntityMapping";
// 给扩展对象增加扩展属性
public static ObjectExtensionInfo MapEfCoreProperty<TProperty>(
[NotNull] this ObjectExtensionInfo objectExtensionInfo,
[NotNull] string propertyName,
[CanBeNull] Action<EntityTypeBuilder, PropertyBuilder>
entityTypeAndPropertyBuildAction)
{
return objectExtensionInfo.MapEfCoreProperty(
typeof(TProperty),
propertyName,
entityTypeAndPropertyBuildAction
);
}
// 给扩展对象增加扩展属性
public static ObjectExtensionInfo MapEfCoreProperty(
[NotNull] this ObjectExtensionInfo objectExtensionInfo,
[NotNull] Type propertyType,
[NotNull] string propertyName,
[CanBeNull] Action<EntityTypeBuilder, PropertyBuilder>
entityTypeAndPropertyBuildAction)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
return objectExtensionInfo.AddOrUpdateProperty(
propertyType,
propertyName,
//objectExtensionInfo 里的 ObjectExtensionPropertyInfo 进行配置
options =>
{
//扩展方法 key: EfCoreMapping value:
// ObjectExtensionPropertyInfoEfCoreMappingOptions
//加入 ObjectExtensionPropertyInfo 的 config 配置字典
options.MapEfCore(
entityTypeAndPropertyBuildAction
);
}
);
}
// 给 ObjectExtensionInfo 增加 EntityTypeBuilder 配置
public static ObjectExtensionInfo MapEfCoreEntity(
[NotNull] this ObjectExtensionInfo objectExtensionInfo,
[NotNull] Action<EntityTypeBuilder> entityTypeBuildAction)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
var mappingOptionList = new List<ObjectExtensionInfoEfCoreMappingOptions>
{
new ObjectExtensionInfoEfCoreMappingOptions(
objectExtensionInfo,
entityTypeBuildAction)
};
// EfCoreEntityMapping
objectExtensionInfo.Configuration.AddOrUpdate(EfCoreEntityConfigurationName,
mappingOptionList,
(k, v) =>
{
v.As<List<ObjectExtensionInfoEfCoreMappingOptions>>().
Add(mappingOptionList.First());
return v;
});
return objectExtensionInfo;
}
// 给 ObjectExtensionInfo 增加 ModelBuilder 配置
public static ObjectExtensionInfo MapEfCoreDbContext(
[NotNull] this ObjectExtensionInfo objectExtensionInfo,
[NotNull] Action<ModelBuilder> modelBuildAction)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
var mappingOptionList = new List<ObjectExtensionInfoEfCoreMappingOptions>
{
new ObjectExtensionInfoEfCoreMappingOptions(
objectExtensionInfo,
modelBuildAction)
};
objectExtensionInfo.Configuration.AddOrUpdate(
EfCoreDbContextConfigurationName, mappingOptionList,
(k, v) =>
{
v.As<List<ObjectExtensionInfoEfCoreMappingOptions>>()
.Add(mappingOptionList.First());
return v;
});
return objectExtensionInfo;
}
//获取上面的配置
public static List<ObjectExtensionInfoEfCoreMappingOptions> GetEfCoreEntityMappings(
[NotNull] this ObjectExtensionInfo objectExtensionInfo)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
return !objectExtensionInfo.Configuration.TryGetValue(
EfCoreEntityConfigurationName, out var options) ?
new List<ObjectExtensionInfoEfCoreMappingOptions>() :
options.As<List<ObjectExtensionInfoEfCoreMappingOptions>>();
}
public static List<ObjectExtensionInfoEfCoreMappingOptions>
GetEfCoreDbContextMappings(
[NotNull] this ObjectExtensionInfo objectExtensionInfo)
{
Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
return !objectExtensionInfo.Configuration.TryGetValue(
EfCoreDbContextConfigurationName, out var options) ?
new List<ObjectExtensionInfoEfCoreMappingOptions>() :
options.As<List<ObjectExtensionInfoEfCoreMappingOptions>>();
}
}
扩展属性增加配置
public static class EfCoreObjectExtensionPropertyInfoExtensions
{
public const string EfCorePropertyConfigurationName = "EfCoreMapping";
[NotNull]
public static ObjectExtensionPropertyInfo MapEfCore(
[NotNull] this ObjectExtensionPropertyInfo propertyExtension)
{
Check.NotNull(propertyExtension, nameof(propertyExtension));
propertyExtension.Configuration[EfCorePropertyConfigurationName] =
new ObjectExtensionPropertyInfoEfCoreMappingOptions(
propertyExtension
);
return propertyExtension;
}
[NotNull]
public static ObjectExtensionPropertyInfo MapEfCore(
[NotNull] this ObjectExtensionPropertyInfo propertyExtension,
Action<EntityTypeBuilder, PropertyBuilder>? entityTypeAndPropertyBuildAction)
{
Check.NotNull(propertyExtension, nameof(propertyExtension));
propertyExtension.Configuration[EfCorePropertyConfigurationName] =
new ObjectExtensionPropertyInfoEfCoreMappingOptions(
propertyExtension,
entityTypeAndPropertyBuildAction
);
return propertyExtension;
}
public static ObjectExtensionPropertyInfoEfCoreMappingOptions? GetEfCoreMappingOrNull(
[NotNull] this ObjectExtensionPropertyInfo propertyExtension)
{
Check.NotNull(propertyExtension, nameof(propertyExtension));
return propertyExtension
.Configuration
.GetOrDefault(EfCorePropertyConfigurationName)
as ObjectExtensionPropertyInfoEfCoreMappingOptions;
}
public static bool IsMappedToFieldForEfCore(
[NotNull] this ObjectExtensionPropertyInfo propertyExtension)
{
Check.NotNull(propertyExtension, nameof(propertyExtension));
return propertyExtension
.Configuration
.ContainsKey(EfCorePropertyConfigurationName);
}
}
扩展上下文
public static class EfCoreObjectExtensionManagerExtensions
{
//建立 TDbContext , ObjectExtensionInfo 绑定关系 在 objectExtensionManager 字典
public static ObjectExtensionManager MapEfCoreDbContext<TDbContext>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Action<ModelBuilder> modelBuilderAction)
where TDbContext : DbContext
{
return objectExtensionManager.AddOrUpdate(
typeof(TDbContext),
options =>
{
options.MapEfCoreDbContext(modelBuilderAction);
});
}
//建立 entityType , ObjectExtensionInfo 绑定关系 在 objectExtensionManager 字典
public static ObjectExtensionManager MapEfCoreEntity<TEntity>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Action<EntityTypeBuilder> entityTypeBuildAction)
where TEntity : IEntity
{
return MapEfCoreEntity(
objectExtensionManager,
typeof(TEntity),
entityTypeBuildAction);
}
//建立 entityType , ObjectExtensionInfo 绑定关系 在 objectExtensionManager 字典
public static ObjectExtensionManager MapEfCoreEntity(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Type entityType,
[NotNull] Action<EntityTypeBuilder> entityTypeBuildAction)
{
Check.NotNull(objectExtensionManager, nameof(objectExtensionManager));
//建立 entityType , ObjectExtensionInfo 绑定关系 在 objectExtensionManager 字典
return objectExtensionManager.AddOrUpdate(
entityType,
options =>
{
options.MapEfCoreEntity(entityTypeBuildAction);
});
}
public static ObjectExtensionManager MapEfCoreProperty<TEntity, TProperty>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] string propertyName)
where TEntity : IHasExtraProperties, IEntity
{
//
return objectExtensionManager.MapEfCoreProperty(
typeof(TEntity),
typeof(TProperty),
propertyName
);
}
// 给 扩展 entityType ,增加 扩展属性
public static ObjectExtensionManager MapEfCoreProperty(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Type entityType,
[NotNull] Type propertyType,
[NotNull] string propertyName)
{
Check.NotNull(objectExtensionManager, nameof(objectExtensionManager));
return objectExtensionManager.AddOrUpdateProperty(
entityType,
propertyType,
propertyName,
options => { options.MapEfCore(); }
);
}
// 给 扩展 entityType ,增加 扩展属性
public static ObjectExtensionManager MapEfCoreProperty<TEntity, TProperty>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] string propertyName,
[CanBeNull] Action<EntityTypeBuilder, PropertyBuilder>
entityTypeAndPropertyBuildAction)
where TEntity : IHasExtraProperties, IEntity
{
return objectExtensionManager.MapEfCoreProperty(
typeof(TEntity),
typeof(TProperty),
propertyName,
entityTypeAndPropertyBuildAction
);
}
//给 扩展 entityType ,增加 扩展属性
public static ObjectExtensionManager MapEfCoreProperty(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] Type entityType,
[NotNull] Type propertyType,
[NotNull] string propertyName,
[CanBeNull] Action<EntityTypeBuilder, PropertyBuilder>
entityTypeAndPropertyBuildAction)
{
Check.NotNull(objectExtensionManager, nameof(objectExtensionManager));
return objectExtensionManager.AddOrUpdateProperty(
entityType,
propertyType,
propertyName,
options =>
{
options.MapEfCore(
entityTypeAndPropertyBuildAction
);
}
);
}
//执行 实体的 objectExtension ,ObjectExtensionPropertyInfo 上的配置
public static void ConfigureEfCoreEntity(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] EntityTypeBuilder typeBuilder)
{
Check.NotNull(objectExtensionManager, nameof(objectExtensionManager));
Check.NotNull(typeBuilder, nameof(typeBuilder));
var objectExtension = objectExtensionManager.GetOrNull(
typeBuilder.Metadata.ClrType);
if (objectExtension == null)
{
return;
}
var efCoreEntityMappings = objectExtension.GetEfCoreEntityMappings();
foreach (var efCoreEntityMapping in efCoreEntityMappings)
{
efCoreEntityMapping.EntityTypeBuildAction?.Invoke(typeBuilder);
}
foreach (var property in objectExtension.GetProperties())
{
var efCoreMapping = property.GetEfCoreMappingOrNull();
if (efCoreMapping == null)
{
continue;
}
/* Prevent multiple calls to the entityTypeBuilder.Property(...) method */
if (typeBuilder.Metadata.FindProperty(property.Name) != null)
{
continue;
}
var propertyBuilder = typeBuilder.Property(property.Type, property.Name);
efCoreMapping.EntityTypeAndPropertyBuildAction?.Invoke(
typeBuilder, propertyBuilder);
efCoreMapping.PropertyBuildAction?.Invoke(propertyBuilder);
}
}
//执行 TDbContext objectExtension 上的配置
public static void ConfigureEfCoreDbContext<TDbContext>(
[NotNull] this ObjectExtensionManager objectExtensionManager,
[NotNull] ModelBuilder modelBuilder)
where TDbContext : DbContext
{
Check.NotNull(objectExtensionManager, nameof(objectExtensionManager));
Check.NotNull(modelBuilder, nameof(modelBuilder));
var objectExtension = objectExtensionManager.GetOrNull(typeof(TDbContext));
if (objectExtension == null)
{
return;
}
var efCoreDbContextMappings = objectExtension.GetEfCoreDbContextMappings();
foreach (var efCoreDbContextMapping in efCoreDbContextMappings)
{
efCoreDbContextMapping.ModelBuildAction?.Invoke(modelBuilder);
}
}
}
EF 提供的 DbContext
EF 的 DbContext 非常复杂的一个上下文类,限制条件一个上下文不能在多个线程里并发的执行因为 DbContext 不支持多线程并发
-
IInfrastructure
:IInfrastructure 是 EF Core 中的内部接口,它允许 DbContext 访问底层的 IServiceProvider。 - IDbContextDependencies:这个接口通常包含了 DbContext 的依赖项,用于内部操作和配置。
- IDbSetCache:这个接口可能用于缓存 DbSet 对象,以提高性能。 4 .IDbContextPoolable:这个 接口可能用于支持 DbContext 的池化,以减少资源消耗。
微软的的定义 A DbContext instance represents a session with the database and can be used to query and save instances of your entities. DbContext is a combination of the Unit Of Work and Repository patterns.
public class DbContext :
IInfrastructure<IServiceProvider>,
IDbContextDependencies,
IDbSetCache,
IDbContextPoolable
{
}
public interface IDbContextDependencies
{
IDbSetSource SetSource { get; }
IEntityFinderFactory EntityFinderFactory { get; }
IAsyncQueryProvider QueryProvider { get; }
IStateManager StateManager { get; }
IChangeDetector ChangeDetector { get; }
IEntityGraphAttacher EntityGraphAttacher { get; }
IExceptionDetector ExceptionDetector { get; }
IDiagnosticsLogger<DbLoggerCategory.Update> UpdateLogger { get; }
IDiagnosticsLogger<DbLoggerCategory.Infrastructure> InfrastructureLogger { get; }
}
public interface IDbSetCache
{
object GetOrAddSet(IDbSetSource source,
[DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type type);
object GetOrAddSet(
IDbSetSource source,
string entityTypeName,
[DynamicallyAccessedMembers(IEntityType.DynamicallyAccessedMemberTypes)] Type type);
IEnumerable<object> GetSets();
}
IEfCoreDbContext abp 定义的上下文接口
IEfCoreDbContext 一样继承 DbContext 的所有接口
public interface IEfCoreDbContext : IDisposable, IInfrastructure<IServiceProvider>,
IDbContextDependencies, IDbSetCache, IDbContextPoolable
{
EntityEntry<TEntity> Attach<TEntity>([NotNull] TEntity entity) where TEntity : class;
EntityEntry Attach([NotNull] object entity);
int SaveChanges();
int SaveChanges(bool acceptAllChangesOnSuccess);
Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken
cancellationToken = default);
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
/// <summary>
/// This method will call the DbContext <see cref="SaveChangesAsync(bool,
///CancellationToken)"/> method directly of EF Core, which doesn't apply concepts of abp.
/// </summary>
Task<int> SaveChangesOnDbContextAsync(bool acceptAllChangesOnSuccess,
CancellationToken cancellationToken = default);
DbSet<T> Set<T>()
where T : class;
DatabaseFacade Database { get; }
ChangeTracker ChangeTracker { get; }
EntityEntry Add([NotNull] object entity);
EntityEntry<TEntity> Add<TEntity>([NotNull] TEntity entity) where TEntity : class;
ValueTask<EntityEntry> AddAsync([NotNull] object entity, CancellationToken
cancellationToken = default);
ValueTask<EntityEntry<TEntity>> AddAsync<TEntity>([NotNull] TEntity entity,
CancellationToken cancellationToken = default) where TEntity : class;
void AddRange([NotNull] IEnumerable<object> entities);
void AddRange([NotNull] params object[] entities);
Task AddRangeAsync([NotNull] params object[] entities);
Task AddRangeAsync([NotNull] IEnumerable<object> entities,
CancellationToken cancellationToken = default);
void AttachRange([NotNull] IEnumerable<object> entities);
void AttachRange([NotNull] params object[] entities);
EntityEntry<TEntity> Entry<TEntity>([NotNull] TEntity entity) where TEntity : class;
EntityEntry Entry([NotNull] object entity);
object? Find([NotNull] Type entityType, [NotNull] params object[] keyValues);
TEntity? Find<TEntity>([NotNull] params object[] keyValues) where TEntity : class;
ValueTask<object?> FindAsync([NotNull] Type entityType, [NotNull] object[] keyValues,
CancellationToken cancellationToken);
ValueTask<TEntity?> FindAsync<TEntity>([NotNull] object[] keyValues,
CancellationToken cancellationToken) where TEntity : class;
ValueTask<TEntity?> FindAsync<TEntity>([NotNull] params object[] keyValues)
where TEntity : class;
ValueTask<object?> FindAsync([NotNull] Type entityType, [NotNull]
params object[] keyValues);
EntityEntry<TEntity> Remove<TEntity>([NotNull] TEntity entity) where TEntity : class;
EntityEntry Remove([NotNull] object entity);
void RemoveRange([NotNull] IEnumerable<object> entities);
void RemoveRange([NotNull] params object[] entities);
EntityEntry<TEntity> Update<TEntity>([NotNull] TEntity entity) where TEntity : class;
EntityEntry Update([NotNull] object entity);
void UpdateRange([NotNull] params object[] entities);
void UpdateRange([NotNull] IEnumerable<object> entities);
}
public class AbpEfCoreDbContextInitializationContext
{
public IUnitOfWork UnitOfWork { get; }
public AbpEfCoreDbContextInitializationContext(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
}
//增加了初始化
public interface IAbpEfCoreDbContext : IEfCoreDbContext
{
//初始化获取到了工作单元
void Initialize(AbpEfCoreDbContextInitializationContext initializationContext);
}
AbpDbContext where TDbContext : DbContext
AbpDbContext ABP 定义自己的上下文,上下文干活要靠 DbContext,但是原来的 DbContext,自带的 工作单元和仓储模式要失效,要不然不能融入 ABP 里
public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext, ITransientDependency
where TDbContext : DbContext
{
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = default!;
protected virtual Guid? CurrentTenantId => CurrentTenant?.Id;
protected virtual bool IsMultiTenantFilterEnabled =>
DataFilter?.IsEnabled<IMultiTenant>() ?? false;
protected virtual bool IsSoftDeleteFilterEnabled =>
DataFilter?.IsEnabled<ISoftDelete>() ?? false;
public ICurrentTenant CurrentTenant =>
LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public IGuidGenerator GuidGenerator =>
LazyServiceProvider.LazyGetService<IGuidGenerator>(SimpleGuidGenerator.Instance);
public IDataFilter DataFilter =>
LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
public IEntityChangeEventHelper EntityChangeEventHelper =>
LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(
NullEntityChangeEventHelper.Instance);
public IAuditPropertySetter AuditPropertySetter =>
LazyServiceProvider.LazyGetRequiredService<IAuditPropertySetter>();
public IEntityHistoryHelper EntityHistoryHelper =>
LazyServiceProvider.LazyGetService<IEntityHistoryHelper>(
NullEntityHistoryHelper.Instance);
public IAuditingManager AuditingManager =>
LazyServiceProvider.LazyGetRequiredService<IAuditingManager>();
public IUnitOfWorkManager UnitOfWorkManager =>
LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
public IClock Clock => LazyServiceProvider.LazyGetRequiredService<IClock>();
public IDistributedEventBus DistributedEventBus =>
LazyServiceProvider.LazyGetRequiredService<IDistributedEventBus>();
public ILocalEventBus LocalEventBus =>
LazyServiceProvider.LazyGetRequiredService<ILocalEventBus>();
public ILogger<AbpDbContext<TDbContext>> Logger =>
LazyServiceProvider.LazyGetService<ILogger<AbpDbContext<TDbContext>>>(
NullLogger<AbpDbContext<TDbContext>>.Instance);
// 为了通过反射调用 这里写成静态方法,因为 db context 里配置的是 Model 里的所有 entity
private static readonly MethodInfo ConfigureBasePropertiesMethodInfo
= typeof(AbpDbContext<TDbContext>)
.GetMethod(
nameof(ConfigureBaseProperties),
BindingFlags.Instance | BindingFlags.NonPublic
)!;
private static readonly MethodInfo ConfigureValueConverterMethodInfo
= typeof(AbpDbContext<TDbContext>)
.GetMethod(
nameof(ConfigureValueConverter),
BindingFlags.Instance | BindingFlags.NonPublic
)!;
private static readonly MethodInfo ConfigureValueGeneratedMethodInfo
= typeof(AbpDbContext<TDbContext>)
.GetMethod(
nameof(ConfigureValueGenerated),
BindingFlags.Instance | BindingFlags.NonPublic
)!;
protected AbpDbContext(DbContextOptions<TDbContext> options)
: base(options)
{
}
// 通过反射的方式进行 entity model 的配置,这里的配置是对所有的模型进行配置
// 这个方法一定会调用,因为是全局的 Entity 配置
// 重写 DBContext 上下文的 IEfCoreDbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// ef core 模型配置默认什么也没做
base.OnModelCreating(modelBuilder);
//给 Model 设置元素据 数据提供者字符串名
TrySetDatabaseProvider(modelBuilder);
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
// 约定的配置属性 审计里的属性, 并发标记
ConfigureBasePropertiesMethodInfo
.MakeGenericMethod(entityType.ClrType)
.Invoke(this, new object[] { modelBuilder, entityType });
// 注册默认的值转换器 AbpDateTimeValueConverter
// abp 没有使用 datetimeOff,故使用了 datetime 值转换器
ConfigureValueConverterMethodInfo
.MakeGenericMethod(entityType.ClrType)
.Invoke(this, new object[] { modelBuilder, entityType });
// 配置默认的值生成器
ConfigureValueGeneratedMethodInfo
.MakeGenericMethod(entityType.ClrType)
.Invoke(this, new object[] { modelBuilder, entityType });
}
}
// 设置数据库提供者
// EfCoreDatabaseProvider 是个枚举类
protected virtual void TrySetDatabaseProvider(ModelBuilder modelBuilder)
{
// 通过 ef 获取到当前的数据库提供程序,并转换为 abp 的枚举字符串
var provider = GetDatabaseProviderOrNull(modelBuilder);
if (provider != null)
{
//给模型统一的设置这个枚举字符串
modelBuilder.SetDatabaseProvider(provider.Value);
}
}
protected virtual EfCoreDatabaseProvider? GetDatabaseProviderOrNull(
ModelBuilder modelBuilder)
{
switch (Database.ProviderName)
{
case "Microsoft.EntityFrameworkCore.SqlServer":
return EfCoreDatabaseProvider.SqlServer;
case "Npgsql.EntityFrameworkCore.PostgreSQL":
return EfCoreDatabaseProvider.PostgreSql;
case "Pomelo.EntityFrameworkCore.MySql":
return EfCoreDatabaseProvider.MySql;
case "Oracle.EntityFrameworkCore":
case "Devart.Data.Oracle.Entity.EFCore":
return EfCoreDatabaseProvider.Oracle;
case "Microsoft.EntityFrameworkCore.Sqlite":
return EfCoreDatabaseProvider.Sqlite;
case "Microsoft.EntityFrameworkCore.InMemory":
return EfCoreDatabaseProvider.InMemory;
case "FirebirdSql.EntityFrameworkCore.Firebird":
return EfCoreDatabaseProvider.Firebird;
case "Microsoft.EntityFrameworkCore.Cosmos":
return EfCoreDatabaseProvider.Cosmos;
default:
return null;
}
}
// 最核心的 SaveChanges ,重写了 父方法
public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess,
CancellationToken cancellationToken = default)
{
try
{
var auditLog = AuditingManager?.Current?.Log;
List<EntityChangeInfo>? entityChangeList = null;
if (auditLog != null)
{
entityChangeList = EntityHistoryHelper.CreateChangeList(
ChangeTracker.Entries().ToList());
}
// 保存扩展属性到数据库 , 如果是修改或删除状态,就更新并发标记
HandlePropertiesBeforeSave();
// 生成领域事件
var eventReport = CreateEventReport();
//调用 db context 的 SaveChangesAsync
var result = await base.SaveChangesAsync(
acceptAllChangesOnSuccess, cancellationToken);
//把领域事件赋值给工作单元后,领域事件清空
PublishEntityEvents(eventReport);
if (entityChangeList != null)
{
EntityHistoryHelper.UpdateChangeList(entityChangeList);
auditLog!.EntityChanges.AddRange(entityChangeList);
Logger.LogDebug($"Added {entityChangeList.Count}
entity changes to the current audit log");
}
return result;
}
catch (DbUpdateConcurrencyException ex)
{
if (ex.Entries.Count > 0)
{
var sb = new StringBuilder();
sb.AppendLine(ex.Entries.Count > 1
? "There are some entries which are not saved due to concurrency exception:"
: "There is an entry which is not saved due to concurrency exception:");
foreach (var entry in ex.Entries)
{
sb.AppendLine(entry.ToString());
}
Logger.LogWarning(sb.ToString());
}
throw new AbpDbConcurrencyException(ex.Message, ex);
}
finally
{
ChangeTracker.AutoDetectChangesEnabled = true;
}
}
// 发布事件
private void PublishEntityEvents(EntityEventReport changeReport)
{
//把领域事件赋值给当前的工作单元了
foreach (var localEvent in changeReport.DomainEvents)
{
UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(
new UnitOfWorkEventRecord(localEvent.EventData.GetType(),
localEvent.EventData, localEvent.EventOrder)
);
}
//把分布式事件赋值给当前的工作单元了
foreach (var distributedEvent in changeReport.DistributedEvents)
{
UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(
new UnitOfWorkEventRecord(distributedEvent.EventData.GetType(),
distributedEvent.EventData, distributedEvent.EventOrder)
);
}
}
//直接执行 db context 的保存,跳过 abp
public virtual Task<int> SaveChangesOnDbContextAsync(bool acceptAllChangesOnSuccess,
CancellationToken cancellationToken = default)
{
return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}
//
public virtual void Initialize(AbpEfCoreDbContextInitializationContext
initializationContext)
{
if (initializationContext.UnitOfWork.Options.Timeout.HasValue &&
Database.IsRelational() &&
!Database.GetCommandTimeout().HasValue)
{
//把工作单元的超时时间给数据库
Database.SetCommandTimeout(TimeSpan.FromMilliseconds(
initializationContext.UnitOfWork.Options.Timeout.Value));
}
//级联删除的时机设置
ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
//实体开始追踪或状态改变的事件发送给工作单元保存
//实体开始被追踪发生的事件
//数据库对象扩展属性的值给到扩展对象的扩展属性
ChangeTracker.Tracked += ChangeTracker_Tracked;
//实体状态变化发生的事件
ChangeTracker.StateChanged += ChangeTracker_StateChanged;
// UnitOfWorkManager ,不使用事务,工作单元内
if (UnitOfWorkManager is AlwaysDisableTransactionsUnitOfWorkManager)
{
// SaveChanges() 不要自动开启事务
Database.AutoTransactionBehavior = AutoTransactionBehavior.Never;
}
}
//发送给工作单元
protected virtual void ChangeTracker_Tracked(object? sender,
EntityTrackedEventArgs e)
{
FillExtraPropertiesForTrackedEntities(e);
PublishEventsForTrackedEntity(e.Entry);
}
//发送给工作单元
protected virtual void ChangeTracker_StateChanged(object? sender,
EntityStateChangedEventArgs e)
{
PublishEventsForTrackedEntity(e.Entry);
}
//那数据库属性的值,赋值给扩展对象的扩展属性
protected virtual void FillExtraPropertiesForTrackedEntities(
EntityTrackedEventArgs e)
{
var entityType = e.Entry.Metadata.ClrType;
if (entityType == null)
{
return;
}
if (!(e.Entry.Entity is IHasExtraProperties entity))
{
return;
}
if (!e.FromQuery)
{
return;
}
var objectExtension = ObjectExtensionManager.Instance.GetOrNull(entityType);
if (objectExtension == null)
{
return;
}
foreach (var property in objectExtension.GetProperties())
{
if (!property.IsMappedToFieldForEfCore())
{
continue;
}
/* Checking "currentValue != null" has a good advantage:
* Assume that you we already using a named extra property,
* then decided to create a field (entity extension) for it.
* In this way, it prevents to delete old value in the JSON and
* updates the field on the next save!
*/
var currentValue = e.Entry.CurrentValues[property.Name];
if (currentValue != null)
{
entity.ExtraProperties[property.Name] = currentValue;
}
}
}
//实体状态改变的事件发送给工作单元保存
private void PublishEventsForTrackedEntity(EntityEntry entry)
{
switch (entry.State)
{
case EntityState.Added:
ApplyAbpConceptsForAddedEntity(entry);
EntityChangeEventHelper.PublishEntityCreatedEvent(entry.Entity);
break;
case EntityState.Modified:
ApplyAbpConceptsForModifiedEntity(entry);
if (entry.Properties.Any(x => x.IsModified &&
x.Metadata.ValueGenerated == ValueGenerated.Never))
{
if (entry.Entity is ISoftDelete &&
entry.Entity.As<ISoftDelete>().IsDeleted)
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
}
else
{
EntityChangeEventHelper.PublishEntityUpdatedEvent(entry.Entity);
}
}
break;
case EntityState.Deleted:
ApplyAbpConceptsForDeletedEntity(entry);
EntityChangeEventHelper.PublishEntityDeletedEvent(entry.Entity);
break;
}
}
// 在保存到数据库的时候,把扩展属性的值保存到数据库 ,如果是修改或删除状态,就更新并发标记
protected virtual void HandlePropertiesBeforeSave()
{
foreach (var entry in ChangeTracker.Entries().ToList())
{
//在保存到数据库的时候,把扩展属性的值保存到数据库
HandleExtraPropertiesOnSave(entry);
// 如果是修改或删除状态,就更新并发标记
if (entry.State.IsIn(EntityState.Modified, EntityState.Deleted))
{
UpdateConcurrencyStamp(entry);
}
}
}
//生成领域事件
protected virtual EntityEventReport CreateEventReport()
{
// 领域事件
var eventReport = new EntityEventReport();
foreach (var entry in ChangeTracker.Entries().ToList())
{
var generatesDomainEventsEntity = entry.Entity as IGeneratesDomainEvents;
if (generatesDomainEventsEntity == null)
{
continue;
}
// 实体或聚合根里获取 LocalEvents
var localEvents = generatesDomainEventsEntity.GetLocalEvents()?.ToArray();
if (localEvents != null && localEvents.Any())
{
eventReport.DomainEvents.AddRange(
localEvents.Select(
eventRecord => new DomainEventEntry(
entry.Entity,
eventRecord.EventData,
eventRecord.EventOrder
)
)
);
//清除实体或聚合根里获取 LocalEvents
generatesDomainEventsEntity.ClearLocalEvents();
}
var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents()?.
ToArray();
if (distributedEvents != null && distributedEvents.Any())
{
eventReport.DistributedEvents.AddRange(
distributedEvents.Select(
eventRecord => new DomainEventEntry(
entry.Entity,
eventRecord.EventData,
eventRecord.EventOrder)
)
);
generatesDomainEventsEntity.ClearDistributedEvents();
}
}
return eventReport;
}
// 处理实体的属性是扩展属性的
protected virtual void HandleExtraPropertiesOnSave(EntityEntry entry)
{
//删除或没有修改的实体不处理
if (entry.State.IsIn(EntityState.Deleted, EntityState.Unchanged))
{
return;
}
// 新增或修改的实体
var entityType = entry.Metadata.ClrType;
if (entityType == null)
{
return;
}
// 不是扩展属性不处理
if (!(entry.Entity is IHasExtraProperties entity))
{
return;
}
//获取 entityType 绑定过的 ObjectExtensionInfo
var objectExtension = ObjectExtensionManager.Instance.GetOrNull(entityType);
if (objectExtension == null)
{
return;
}
// 属性 ObjectExtensionPropertyInfo 的 Configuration 配置过 EfCoreMapping
var efMappedProperties = ObjectExtensionManager.Instance
.GetProperties(entityType)
.Where(p => p.IsMappedToFieldForEfCore());
// ObjectExtensionPropertyInfo
foreach (var property in efMappedProperties)
{
//实体有此配置属性
if (!entity.HasProperty(property.Name))
{
continue;
}
//获取的是数据库模型的属性
var entryProperty = entry.Property(property.Name);
//获取的是扩展对象的属性
var entityProperty = entity.GetProperty(property.Name);
//扩展属性没有值
if (entityProperty == null)
{
//数据库模型对象默认也给 null
entryProperty.CurrentValue = null;
continue;
}
//类型相等就把扩展属性的值赋给数据库模型
if (entryProperty.Metadata.ClrType == entityProperty.GetType())
{
entryProperty.CurrentValue = entityProperty;
}
//属性的类型不相等
else
{
// 是私有类型 或 datetime guid decimal
if (TypeHelper.IsPrimitiveExtended(entryProperty.Metadata.ClrType,
includeEnums: true))
{
var conversionType = entryProperty.Metadata.ClrType;
if (TypeHelper.IsNullable(conversionType))
{
conversionType = conversionType.
GetFirstGenericArgumentIfNullable();
}
if (conversionType == typeof(Guid))
{
entryProperty.CurrentValue = TypeDescriptor.GetConverter(
conversionType).ConvertFromInvariantString(
entityProperty.ToString()!);
}
else if (conversionType.IsEnum)
{
entryProperty.CurrentValue = Enum.Parse(conversionType,
entityProperty.ToString()!, ignoreCase: true);
}
else
{
entryProperty.CurrentValue = Convert.ChangeType(
entityProperty, conversionType, CultureInfo.InvariantCulture);
}
}
}
}
}
//在实体增加的时候, 给 继承相应接口的实体相应属性的赋值
protected virtual void ApplyAbpConceptsForAddedEntity(EntityEntry entry)
{
//在实体被新增的时候,在不是数据库新增的情况下,生成新的 id
CheckAndSetId(entry);
//在实体被新增的时候,设置并发属性的值
SetConcurrencyStampIfNull(entry);
//如果实体继承了 audit 接口,给这些接口相应字段赋值
SetCreationAuditProperties(entry);
}
// 在实体修改或软删除的时候, 给 继承相应接口的实体相应属性的赋值
protected virtual void ApplyAbpConceptsForModifiedEntity(EntityEntry entry)
{
if (entry.State == EntityState.Modified && entry.Properties.Any(x => x.IsModified
&& (x.Metadata.ValueGenerated == ValueGenerated.Never ||
x.Metadata.ValueGenerated == ValueGenerated.OnAdd)))
{
IncrementEntityVersionProperty(entry);
SetModificationAuditProperties(entry);
if (entry.Entity is ISoftDelete && entry.Entity.As<ISoftDelete>().IsDeleted)
{
SetDeletionAuditProperties(entry);
}
}
}
//删除的时候,设置一些属性
protected virtual void ApplyAbpConceptsForDeletedEntity(EntityEntry entry)
{
if (!(entry.Entity is ISoftDelete))
{
return;
}
if (IsHardDeleted(entry))
{
return;
}
entry.Reload();
ObjectHelper.TrySetProperty(entry.Entity.As<ISoftDelete>(),
x => x.IsDeleted, () => true);
SetDeletionAuditProperties(entry);
}
//硬删除
protected virtual bool IsHardDeleted(EntityEntry entry)
{
var hardDeletedEntities = UnitOfWorkManager?.Current?.Items.
GetOrDefault(UnitOfWorkItemNames.HardDeletedEntities) as HashSet<IEntity>;
if (hardDeletedEntities == null)
{
return false;
}
return hardDeletedEntities.Contains(entry.Entity);
}
//更新并发值
protected virtual void UpdateConcurrencyStamp(EntityEntry entry)
{
var entity = entry.Entity as IHasConcurrencyStamp;
if (entity == null)
{
return;
}
Entry(entity).Property(x => x.ConcurrencyStamp).OriginalValue =
entity.ConcurrencyStamp;
entity.ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
protected virtual void SetConcurrencyStampIfNull(EntityEntry entry)
{
var entity = entry.Entity as IHasConcurrencyStamp;
if (entity == null)
{
return;
}
if (entity.ConcurrencyStamp != null)
{
return;
}
entity.ConcurrencyStamp = Guid.NewGuid().ToString("N");
}
//设置 id
protected virtual void CheckAndSetId(EntityEntry entry)
{
if (entry.Entity is IEntity<Guid> entityWithGuidId)
{
TrySetGuidId(entry, entityWithGuidId);
}
}
protected virtual void TrySetGuidId(EntityEntry entry, IEntity<Guid> entity)
{
if (entity.Id != default)
{
return;
}
var idProperty = entry.Property("Id").Metadata.PropertyInfo!;
//Check for DatabaseGeneratedAttribute
var dbGeneratedAttr = ReflectionHelper
.GetSingleAttributeOrDefault<DatabaseGeneratedAttribute>(
idProperty
);
if (dbGeneratedAttr != null && dbGeneratedAttr.DatabaseGeneratedOption !=
DatabaseGeneratedOption.None)
{
return;
}
EntityHelper.TrySetId(
entity,
() => GuidGenerator.Create(),
true
);
}
protected virtual void SetCreationAuditProperties(EntityEntry entry)
{
AuditPropertySetter?.SetCreationProperties(entry.Entity);
}
protected virtual void SetModificationAuditProperties(EntityEntry entry)
{
AuditPropertySetter?.SetModificationProperties(entry.Entity);
}
protected virtual void SetDeletionAuditProperties(EntityEntry entry)
{
AuditPropertySetter?.SetDeletionProperties(entry.Entity);
}
protected virtual void IncrementEntityVersionProperty(EntityEntry entry)
{
AuditPropertySetter?.IncrementEntityVersionProperty(entry.Entity);
}
//约定的配置属性 审计里的属性, 并发标记
protected virtual void ConfigureBaseProperties<TEntity>(ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType)
where TEntity : class
{
if (mutableEntityType.IsOwned())
{
return;
}
if (!typeof(IEntity).IsAssignableFrom(typeof(TEntity)))
{
return;
}
modelBuilder.Entity<TEntity>().ConfigureByConvention();
ConfigureGlobalFilters<TEntity>(modelBuilder, mutableEntityType);
}
//配置全局过滤器
protected virtual void ConfigureGlobalFilters<TEntity>(ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType)
where TEntity : class
{
//实体继承了相应的过滤器
if (mutableEntityType.BaseType == null && ShouldFilterEntity<TEntity>(
mutableEntityType))
{
var filterExpression = CreateFilterExpression<TEntity>();
if (filterExpression != null)
{
//对实体加全局过滤器,abp 定义的过滤器都是查询过滤器
modelBuilder.Entity<TEntity>().HasAbpQueryFilter(filterExpression);
}
}
}
// 配置默认的值转换程序 abp 默认就 data time 类型有值转换程序
protected virtual void ConfigureValueConverter<TEntity>(ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType)
where TEntity : class
{
if (mutableEntityType.BaseType == null &&
!typeof(TEntity).IsDefined(typeof(DisableDateTimeNormalizationAttribute),
true) &&
!typeof(TEntity).IsDefined(typeof(OwnedAttribute), true) &&
!mutableEntityType.IsOwned())
{
if (LazyServiceProvider == null || Clock == null)
{
return;
}
foreach (var property in mutableEntityType.GetProperties().
Where(property => property.PropertyInfo != null &&
(property.PropertyInfo.PropertyType ==
typeof(DateTime) ||
property.PropertyInfo.PropertyType == typeof(DateTime?)) &&
property.PropertyInfo.CanWrite &&
ReflectionHelper.
GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<
DisableDateTimeNormalizationAttribute>(
property.PropertyInfo) == null))
{
modelBuilder
.Entity<TEntity>()
.Property(property.Name)
.HasConversion(property.ClrType == typeof(DateTime)
? new AbpDateTimeValueConverter(Clock)
: new AbpNullableDateTimeValueConverter(Clock));
}
}
}
// guid 的主键不要用 数据库生成
protected virtual void ConfigureValueGenerated<TEntity>(ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType)
where TEntity : class
{
// 不是 IEntity<Guid> 类型
if (!typeof(IEntity<Guid>).IsAssignableFrom(typeof(TEntity)))
{
return;
}
// 是 IEntity<Guid> 类型,但是 Id 属性明确是由数据库生成
var idPropertyBuilder = modelBuilder.Entity<TEntity>().
Property(x => ((IEntity<Guid>)x).Id);
if (idPropertyBuilder.Metadata.PropertyInfo!.
IsDefined(typeof(DatabaseGeneratedAttribute), true))
{
return;
}
// IEntity<Guid> 的 ID 明确告诉数据库不要生成,由程序生成
idPropertyBuilder.ValueGeneratedNever();
}
//实体是否能被使用过滤器
protected virtual bool ShouldFilterEntity<TEntity>(
IMutableEntityType entityType) where TEntity : class
{
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
return false;
}
//
protected virtual Expression<Func<TEntity, bool>>?
CreateFilterExpression<TEntity>()
where TEntity : class
{
Expression<Func<TEntity, bool>>? expression = null;
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
expression = e => !IsSoftDeleteFilterEnabled ||
!EF.Property<bool>(e, "IsDeleted");
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> multiTenantFilter = e =>
!IsMultiTenantFilterEnabled ||
EF.Property<Guid>(e, "TenantId") == CurrentTenantId;
expression = expression == null ? multiTenantFilter :
QueryFilterExpressionHelper.CombineExpressions(expression, multiTenantFilter);
}
return expression;
}
}
AbpEntityTypeBuilderExtensions 实体的约定配置
public static class AbpEntityTypeBuilderExtensions
{
public static void ConfigureByConvention(this EntityTypeBuilder b)
{
//配置并发标记,数据库字段长度
b.TryConfigureConcurrencyStamp();
// 额外的属性,序列化为json 保存到数据库 ,实体需要实现 IHasExtraProperties 接口,
//并且额外的属性保存在固定的
// ExtraPropertyDictionary 字段里
b.TryConfigureExtraProperties();
// 额外的属性,在数据库里保存为单独的指定数据类型的字段
// 这个是 EF 里的影子属性
// 也需要 实体需要实现 IHasExtraProperties 接口
b.TryConfigureObjectExtensions();
//以下都是为审计设置属性在数据库必须等属性
b.TryConfigureMayHaveCreator();
b.TryConfigureMustHaveCreator();
b.TryConfigureSoftDelete();
b.TryConfigureDeletionTime();
b.TryConfigureDeletionAudited();
b.TryConfigureCreationTime();
b.TryConfigureLastModificationTime();
b.TryConfigureModificationAudited();
// 设置租户 数据库 Required
b.TryConfigureMultiTenant();
}
public static void ConfigureConcurrencyStamp<T>(this EntityTypeBuilder<T> b)
where T : class, IHasConcurrencyStamp
{
b.As<EntityTypeBuilder>().TryConfigureConcurrencyStamp();
}
public static void TryConfigureConcurrencyStamp(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IHasConcurrencyStamp>())
{
b.Property(nameof(IHasConcurrencyStamp.ConcurrencyStamp))
.IsConcurrencyToken()
.HasMaxLength(ConcurrencyStampConsts.MaxLength)
.HasColumnName(nameof(IHasConcurrencyStamp.ConcurrencyStamp));
}
}
public static void ConfigureExtraProperties<T>(this EntityTypeBuilder<T> b)
where T : class, IHasExtraProperties
{
b.As<EntityTypeBuilder>().TryConfigureExtraProperties();
}
public static void TryConfigureExtraProperties(this EntityTypeBuilder b)
{
if (!b.Metadata.ClrType.IsAssignableTo<IHasExtraProperties>())
{
return;
}
b.Property<ExtraPropertyDictionary>(nameof(IHasExtraProperties.ExtraProperties))
.HasColumnName(nameof(IHasExtraProperties.ExtraProperties))
.HasConversion(new ExtraPropertiesValueConverter(b.Metadata.ClrType))
.Metadata.SetValueComparer(new ExtraPropertyDictionaryValueComparer());
b.TryConfigureObjectExtensions();
}
public static void ConfigureObjectExtensions<T>(this EntityTypeBuilder<T> b)
where T : class, IHasExtraProperties
{
b.As<EntityTypeBuilder>().TryConfigureObjectExtensions();
}
public static void TryConfigureObjectExtensions(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IHasExtraProperties>())
{
ObjectExtensionManager.Instance.ConfigureEfCoreEntity(b);
}
}
public static void ApplyObjectExtensionMappings(this EntityTypeBuilder b)
{
ObjectExtensionManager.Instance.ConfigureEfCoreEntity(b);
}
public static void ConfigureSoftDelete<T>(this EntityTypeBuilder<T> b)
where T : class, ISoftDelete
{
b.As<EntityTypeBuilder>().TryConfigureSoftDelete();
}
public static void TryConfigureSoftDelete(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<ISoftDelete>())
{
b.Property(nameof(ISoftDelete.IsDeleted))
.IsRequired()
.HasDefaultValue(false)
.HasColumnName(nameof(ISoftDelete.IsDeleted));
}
}
public static void ConfigureDeletionTime<T>(this EntityTypeBuilder<T> b)
where T : class, IHasDeletionTime
{
b.As<EntityTypeBuilder>().TryConfigureDeletionTime();
}
public static void TryConfigureDeletionTime(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IHasDeletionTime>())
{
b.TryConfigureSoftDelete();
b.Property(nameof(IHasDeletionTime.DeletionTime))
.IsRequired(false)
.HasColumnName(nameof(IHasDeletionTime.DeletionTime));
}
}
public static void ConfigureMayHaveCreator<T>(this EntityTypeBuilder<T> b)
where T : class, IMayHaveCreator
{
b.As<EntityTypeBuilder>().TryConfigureMayHaveCreator();
}
public static void TryConfigureMayHaveCreator(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IMayHaveCreator>())
{
b.Property(nameof(IMayHaveCreator.CreatorId))
.IsRequired(false)
.HasColumnName(nameof(IMayHaveCreator.CreatorId));
}
}
public static void ConfigureMustHaveCreator<T>(this EntityTypeBuilder<T> b)
where T : class, IMustHaveCreator
{
b.As<EntityTypeBuilder>().TryConfigureMustHaveCreator();
}
public static void TryConfigureMustHaveCreator(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IMustHaveCreator>())
{
b.Property(nameof(IMustHaveCreator.CreatorId))
.IsRequired()
.HasColumnName(nameof(IMustHaveCreator.CreatorId));
}
}
public static void ConfigureDeletionAudited<T>(this EntityTypeBuilder<T> b)
where T : class, IDeletionAuditedObject
{
b.As<EntityTypeBuilder>().TryConfigureDeletionAudited();
}
public static void TryConfigureDeletionAudited(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IDeletionAuditedObject>())
{
b.TryConfigureDeletionTime();
b.Property(nameof(IDeletionAuditedObject.DeleterId))
.IsRequired(false)
.HasColumnName(nameof(IDeletionAuditedObject.DeleterId));
}
}
public static void ConfigureCreationTime<T>(this EntityTypeBuilder<T> b)
where T : class, IHasCreationTime
{
b.As<EntityTypeBuilder>().TryConfigureCreationTime();
}
public static void TryConfigureCreationTime(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IHasCreationTime>())
{
b.Property(nameof(IHasCreationTime.CreationTime))
.IsRequired()
.HasColumnName(nameof(IHasCreationTime.CreationTime));
}
}
public static void ConfigureCreationAudited<T>(this EntityTypeBuilder<T> b)
where T : class, ICreationAuditedObject
{
b.As<EntityTypeBuilder>().TryConfigureCreationAudited();
}
public static void TryConfigureCreationAudited(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<ICreationAuditedObject>())
{
b.As<EntityTypeBuilder>().TryConfigureCreationTime();
b.As<EntityTypeBuilder>().TryConfigureMayHaveCreator();
}
}
public static void ConfigureLastModificationTime<T>(this EntityTypeBuilder<T> b)
where T : class, IHasModificationTime
{
b.As<EntityTypeBuilder>().TryConfigureLastModificationTime();
}
public static void TryConfigureLastModificationTime(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IHasModificationTime>())
{
b.Property(nameof(IHasModificationTime.LastModificationTime))
.IsRequired(false)
.HasColumnName(nameof(IHasModificationTime.LastModificationTime));
}
}
public static void ConfigureModificationAudited<T>(this EntityTypeBuilder<T> b)
where T : class, IModificationAuditedObject
{
b.As<EntityTypeBuilder>().TryConfigureModificationAudited();
}
public static void TryConfigureModificationAudited(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IModificationAuditedObject>())
{
b.TryConfigureLastModificationTime();
b.Property(nameof(IModificationAuditedObject.LastModifierId))
.IsRequired(false)
.HasColumnName(nameof(IModificationAuditedObject.LastModifierId));
}
}
public static void ConfigureAudited<T>(this EntityTypeBuilder<T> b)
where T : class, IAuditedObject
{
b.As<EntityTypeBuilder>().TryConfigureAudited();
}
public static void TryConfigureAudited(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IAuditedObject>())
{
b.As<EntityTypeBuilder>().TryConfigureCreationAudited();
b.As<EntityTypeBuilder>().TryConfigureModificationAudited();
}
}
public static void ConfigureFullAudited<T>(this EntityTypeBuilder<T> b)
where T : class, IFullAuditedObject
{
b.As<EntityTypeBuilder>().TryConfigureFullAudited();
}
public static void TryConfigureFullAudited(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IFullAuditedObject>())
{
b.As<EntityTypeBuilder>().TryConfigureAudited();
b.As<EntityTypeBuilder>().TryConfigureDeletionAudited();
}
}
public static void ConfigureMultiTenant<T>(this EntityTypeBuilder<T> b)
where T : class, IMultiTenant
{
b.As<EntityTypeBuilder>().TryConfigureMultiTenant();
}
public static void TryConfigureMultiTenant(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IMultiTenant>())
{
b.Property(nameof(IMultiTenant.TenantId))
.IsRequired(false)
.HasColumnName(nameof(IMultiTenant.TenantId));
}
}
public static void ConfigureCreationAuditedAggregateRoot<T>(this
EntityTypeBuilder<T> b)
where T : class
{
b.As<EntityTypeBuilder>().TryConfigureCreationAudited();
b.As<EntityTypeBuilder>().TryConfigureExtraProperties();
b.As<EntityTypeBuilder>().TryConfigureConcurrencyStamp();
}
public static void ConfigureAuditedAggregateRoot<T>(this EntityTypeBuilder<T> b)
where T : class
{
b.As<EntityTypeBuilder>().TryConfigureAudited();
b.As<EntityTypeBuilder>().TryConfigureExtraProperties();
b.As<EntityTypeBuilder>().TryConfigureConcurrencyStamp();
}
public static void ConfigureFullAuditedAggregateRoot<T>(this EntityTypeBuilder<T> b)
where T : class
{
b.As<EntityTypeBuilder>().TryConfigureFullAudited();
b.As<EntityTypeBuilder>().TryConfigureExtraProperties();
b.As<EntityTypeBuilder>().TryConfigureConcurrencyStamp();
}
//TODO: Add other interfaces (IAuditedObject<TUser>...)
}
通过配置生成 AbpDbContext
AbpDbContextOptions AbpDbContext 配置选项
AbpDbContextConfigurationContext 配置上下文,提供能配置的条目
public class AbpDbContextConfigurationContext : IServiceProviderAccessor
{
public IServiceProvider ServiceProvider { get; }
//连接字符串
public string ConnectionString { get; }
public string? ConnectionStringName { get; }
// ef 数据库连接
public DbConnection? ExistingConnection { get; }
// ef 数据库连接选项进行配置
public DbContextOptionsBuilder DbContextOptions { get; protected set; }
public AbpDbContextConfigurationContext(
[NotNull] string connectionString,
[NotNull] IServiceProvider serviceProvider,
string? connectionStringName,
DbConnection? existingConnection)
{
ConnectionString = connectionString;
ServiceProvider = serviceProvider;
ConnectionStringName = connectionStringName;
ExistingConnection = existingConnection;
DbContextOptions = new DbContextOptionsBuilder()
.UseLoggerFactory(serviceProvider.GetRequiredService<ILoggerFactory>())
.UseApplicationServiceProvider(serviceProvider);
}
}
// 带 TDbContext 上下文的配置选项
public class AbpDbContextConfigurationContext<TDbContext> :
AbpDbContextConfigurationContext
where TDbContext : AbpDbContext<TDbContext>
{
public new DbContextOptionsBuilder<TDbContext> DbContextOptions =>
(DbContextOptionsBuilder<TDbContext>)base.DbContextOptions;
public AbpDbContextConfigurationContext(
string connectionString,
[NotNull] IServiceProvider serviceProvider,
string? connectionStringName,
DbConnection? existingConnection)
: base(
connectionString,
serviceProvider,
connectionStringName,
existingConnection)
{
base.DbContextOptions = new DbContextOptionsBuilder<TDbContext>()
.UseLoggerFactory(serviceProvider.GetRequiredService<ILoggerFactory>())
.UseApplicationServiceProvider(serviceProvider); ;
}
}
AbpDbContextOptions AbpDbContext 配置选项
此类主要时在数据库提供程序实现者里使用,EF CORE MYSQL 里使用此类生成 AbpDbContext
public class AbpDbContextOptions
{
//在生成 AbpDbContextOptions 前执行的行为
internal List<Action<AbpDbContextConfigurationContext>>
DefaultPreConfigureActions { get; }
// 在生成 AbpDbContextOptions 时 执行的行为
internal Action<AbpDbContextConfigurationContext>?
DefaultConfigureAction { get; set; }
//在生成 AbpDbContextOptions 前执行的行为, 保存 TDbContext 的配置行为
internal Dictionary<Type, List<object>> PreConfigureActions { get; }
// 在生成 AbpDbContextOptions 时 执行的行为,保存 TDbContext 的配置行为
internal Dictionary<Type, object> ConfigureActions { get; }
//租户 和 DbContext 的对于关系,不同的租户可以有不同的 DbContext
internal Dictionary<MultiTenantDbContextType, Type> DbContextReplacements { get; }
public AbpDbContextOptions()
{
DefaultPreConfigureActions = new List<Action<AbpDbContextConfigurationContext>>();
PreConfigureActions = new Dictionary<Type, List<object>>();
ConfigureActions = new Dictionary<Type, object>();
DbContextReplacements = new Dictionary<MultiTenantDbContextType, Type>();
}
public void PreConfigure([NotNull] Action<AbpDbContextConfigurationContext> action)
{
Check.NotNull(action, nameof(action));
DefaultPreConfigureActions.Add(action);
}
public void Configure([NotNull] Action<AbpDbContextConfigurationContext> action)
{
Check.NotNull(action, nameof(action));
DefaultConfigureAction = action;
}
public bool IsConfiguredDefault()
{
return DefaultConfigureAction != null;
}
public void PreConfigure<TDbContext>(
[NotNull] Action<AbpDbContextConfigurationContext<TDbContext>> action)
where TDbContext : AbpDbContext<TDbContext>
{
Check.NotNull(action, nameof(action));
var actions = PreConfigureActions.GetOrDefault(typeof(TDbContext));
if (actions == null)
{
PreConfigureActions[typeof(TDbContext)] = actions = new List<object>();
}
actions.Add(action);
}
public void Configure<TDbContext>(
[NotNull] Action<AbpDbContextConfigurationContext<TDbContext>> action)
where TDbContext : AbpDbContext<TDbContext>
{
Check.NotNull(action, nameof(action));
ConfigureActions[typeof(TDbContext)] = action;
}
public bool IsConfigured<TDbContext>()
{
return IsConfigured(typeof(TDbContext));
}
public bool IsConfigured(Type dbContextType)
{
return ConfigureActions.ContainsKey(dbContextType);
}
// DbContextReplacements 里看有没有匹配的 dbContextType
internal Type GetReplacedTypeOrSelf(
Type dbContextType, MultiTenancySides multiTenancySides = MultiTenancySides.Both)
{
var replacementType = dbContextType;
while (true)
{
//在预配置的服务里匹配可以换的 dbContextType
var foundType = DbContextReplacements.
LastOrDefault(
x => x.Key.Type == replacementType &&
x.Key.MultiTenancySide.HasFlag(multiTenancySides));
if (!foundType.Equals(default(KeyValuePair<MultiTenantDbContextType, Type>)))
{
if (foundType.Value == dbContextType)
{
throw new AbpException(
"Circular DbContext replacement found for " +
dbContextType.AssemblyQualifiedName
);
}
// 没找到继续找
replacementType = foundType.Value;
}
else
{
//找到匹配的
return replacementType;
}
}
}
}
IDbContextProvider DbContextProvider 提供者
public interface IDbContextProvider<TDbContext>
where TDbContext : IEfCoreDbContext
{
Task<TDbContext> GetDbContextAsync();
}
ef core 实现工作单元内定义的接口
ef core 实现 ITransactionApi
public class EfCoreTransactionApi : ITransactionApi, ISupportsRollback
{
public IDbContextTransaction DbContextTransaction { get; }
public IEfCoreDbContext StarterDbContext { get; }
public List<IEfCoreDbContext> AttendedDbContexts { get; }
protected ICancellationTokenProvider CancellationTokenProvider { get; }
public EfCoreTransactionApi(
//使用数据库的事务提供器
IDbContextTransaction dbContextTransaction,
//数据库上下文
IEfCoreDbContext starterDbContext,
ICancellationTokenProvider cancellationTokenProvider)
{
DbContextTransaction = dbContextTransaction;
StarterDbContext = starterDbContext;
CancellationTokenProvider = cancellationTokenProvider;
AttendedDbContexts = new List<IEfCoreDbContext>();
}
public async Task CommitAsync(CancellationToken cancellationToken = default)
{
foreach (var dbContext in AttendedDbContexts)
{
if (dbContext.As<DbContext>().HasRelationalTransactionManager() &&
// DbContextTransaction.GetDbTransaction() 获取 DbTransaction
// 当前数据库上下文使用的数据库连接和 当前开启的事务使用的数据库连接相同
dbContext.Database.GetDbConnection() ==
DbContextTransaction.GetDbTransaction().Connection)
{
continue;
//Relational databases use the shared
//transaction if they are using the same connection
}
//如果连接使用的事务不是当前的事务,对连接上的事务单独提交
await dbContext.Database.CommitTransactionAsync(
CancellationTokenProvider.FallbackToProvider(cancellationToken));
}
//当前的事务提交
await DbContextTransaction.CommitAsync(
CancellationTokenProvider.FallbackToProvider(cancellationToken));
}
public void Dispose()
{
DbContextTransaction.Dispose();
}
//回滚提交
public async Task RollbackAsync(CancellationToken cancellationToken)
{
foreach (var dbContext in AttendedDbContexts)
{
if (dbContext.As<DbContext>().HasRelationalTransactionManager() &&
dbContext.Database.GetDbConnection() ==
DbContextTransaction.GetDbTransaction().Connection)
{
continue; //Relational databases use the
// shared transaction if they are using the same connection
}
await dbContext.Database.RollbackTransactionAsync(
CancellationTokenProvider.FallbackToProvider(cancellationToken));
}
await DbContextTransaction.RollbackAsync(
CancellationTokenProvider.FallbackToProvider(cancellationToken));
}
}
Ef Core 实现 IDatabaseApi
public class EfCoreDatabaseApi : IDatabaseApi, ISupportsSavingChanges
{
public IEfCoreDbContext DbContext { get; }
public EfCoreDatabaseApi(IEfCoreDbContext dbContext)
{
DbContext = dbContext;
}
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
{
return DbContext.SaveChangesAsync(cancellationToken);
}
}
在工作单元内获取 IDbContext
为什么是工作单元获取事务,因为工作单元可以是事务性的,此事务可以在不同的数据库上下文之间 进行复用,只要使用的数据库链接时同样的
public class UnitOfWorkDbContextProvider<TDbContext> : IDbContextProvider<TDbContext>
where TDbContext : IEfCoreDbContext
{
private const string TransactionsNotSupportedWarningMessage =
"Current database does not support transactions. Your
database may remain in an inconsistent state in an error case.";
public ILogger<UnitOfWorkDbContextProvider<TDbContext>> Logger { get; set; }
protected readonly IUnitOfWorkManager UnitOfWorkManager;
protected readonly IConnectionStringResolver ConnectionStringResolver;
protected readonly ICancellationTokenProvider CancellationTokenProvider;
protected readonly ICurrentTenant CurrentTenant;
//获取当前的 EfCoreDbContextType 类型
protected readonly IEfCoreDbContextTypeProvider EfCoreDbContextTypeProvider;
public UnitOfWorkDbContextProvider(
IUnitOfWorkManager unitOfWorkManager,
IConnectionStringResolver connectionStringResolver,
ICancellationTokenProvider cancellationTokenProvider,
ICurrentTenant currentTenant,
IEfCoreDbContextTypeProvider efCoreDbContextTypeProvider)
{
UnitOfWorkManager = unitOfWorkManager;
ConnectionStringResolver = connectionStringResolver;
CancellationTokenProvider = cancellationTokenProvider;
CurrentTenant = currentTenant;
EfCoreDbContextTypeProvider = efCoreDbContextTypeProvider;
Logger = NullLogger<UnitOfWorkDbContextProvider<TDbContext>>.Instance;
}
public virtual async Task<TDbContext> GetDbContextAsync()
{
var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null)
{
throw new AbpException(
"A DbContext can only be created inside a unit of work!");
}
// 获取真实的 DbContextType,因为有可能被替换
var targetDbContextType = EfCoreDbContextTypeProvider.
GetDbContextType(typeof(TDbContext));
// 获取链接字符串名
var connectionStringName = ConnectionStringNameAttribute.
GetConnStringName(targetDbContextType);
// 获取链接字符串
var connectionString = await ResolveConnectionStringAsync(connectionStringName);
var dbContextKey = $"{targetDbContextType.FullName}_{connectionString}";
//因为 一个 unitOfWork 里可以有多个数据库上下文及其绑定的连接字符串,
//这里获取要使用的 db context
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
if (databaseApi == null)
{
databaseApi = new EfCoreDatabaseApi(
//生成数据库上下文
await CreateDbContextAsync(unitOfWork,
connectionStringName, connectionString)
);
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
}
return (TDbContext)((EfCoreDatabaseApi)databaseApi).DbContext;
}
//
protected virtual async Task<TDbContext> CreateDbContextAsync(
IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
{
//
var creationContext = new DbContextCreationContext(
connectionStringName, connectionString);
//使用 creationContext 的值临时替换 DbContextCreationContext 的 当前值
//结束的时候恢复之前的值
using (DbContextCreationContext.Use(creationContext))
{
// 生成一个数据库上下文,此上下文时瞬死的,数据库上下文可以复用事务
var dbContext = await CreateDbContextAsync(unitOfWork);
if (dbContext is IAbpEfCoreDbContext abpEfCoreDbContext)
{
//设置生成的数据库上下文的工作单元为当前
abpEfCoreDbContext.Initialize(
new AbpEfCoreDbContextInitializationContext(
unitOfWork
)
);
}
return dbContext;
}
}
//获取数据库上下文
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork)
{
return unitOfWork.Options.IsTransactional
? await CreateDbContextWithTransactionAsync(unitOfWork)
: unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
}
//生成事务的 DbContext
protected virtual async Task<TDbContext>
CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
{
var transactionApiKey = $"EntityFrameworkCore_{
DbContextCreationContext.Current.ConnectionString}";
//判断工作单元内是否有存在的指定的事务,依据连接字符串
var activeTransaction = unitOfWork.FindTransactionApi(
transactionApiKey) as EfCoreTransactionApi;
if (activeTransaction == null)
{
//服务定位器获得当前的数据库上下文,此上下文时瞬时的
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
try
{
// 生成一个 IDbContextTransaction
var dbTransaction = unitOfWork.Options.IsolationLevel.HasValue
? await dbContext.Database.BeginTransactionAsync(
unitOfWork.Options.IsolationLevel.Value, GetCancellationToken())
: await dbContext.Database.BeginTransactionAsync(
GetCancellationToken());
//利用生成的数据库上下文,生成事务,并把此事务保存到此工作单元内
unitOfWork.AddTransactionApi(
transactionApiKey,
new EfCoreTransactionApi(
dbTransaction,
dbContext,
CancellationTokenProvider
)
);
}
catch (Exception e) when (e is InvalidOperationException ||
e is NotSupportedException)
{
Logger.LogWarning(TransactionsNotSupportedWarningMessage);
return dbContext;
}
return dbContext;
}
else
{
//数据库连接上下文里更换连接到当前工作单元内存在的事务
DbContextCreationContext.Current.ExistingConnection =
activeTransaction.DbContextTransaction.GetDbTransaction().Connection;
//获取上下文
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
if (dbContext.As<DbContext>().HasRelationalTransactionManager())
{
if (dbContext.Database.GetDbConnection() ==
DbContextCreationContext.Current.ExistingConnection)
{
//更改当前数据库上下文的事务为当前工作单元内激活的事务
await dbContext.Database.UseTransactionAsync(
activeTransaction.DbContextTransaction.GetDbTransaction(),
GetCancellationToken());
}
else
{
try
{
/* User did not re-use the ExistingConnection and we
are starting a new transaction.
EfCoreTransactionApi will check the connection
string match and separately
commit/rollback this transaction
over the DbContext instance. */
if (unitOfWork.Options.IsolationLevel.HasValue)
{
await dbContext.Database.BeginTransactionAsync(
unitOfWork.Options.IsolationLevel.Value,
GetCancellationToken()
);
}
else
{
await dbContext.Database.BeginTransactionAsync(
GetCancellationToken()
);
}
}
catch (Exception e) when (e is InvalidOperationException ||
e is NotSupportedException)
{
Logger.LogWarning(TransactionsNotSupportedWarningMessage);
return dbContext;
}
}
}
else
{
try
{
/* No need to store the returning IDbContextTransaction
for non-relational databases
* since EfCoreTransactionApi will handle the
commit/rollback over the DbContext instance.
*/
// EfCoreTransactionApi 非关系性数据库的事务没有提交等
api 不需要进行保存到字典
await dbContext.Database.BeginTransactionAsync(
GetCancellationToken());
}
catch (Exception e) when (e is InvalidOperationException
|| e is NotSupportedException)
{
Logger.LogWarning(TransactionsNotSupportedWarningMessage);
return dbContext;
}
}
activeTransaction.AttendedDbContexts.Add(dbContext);
return dbContext;
}
}
//获取当前的连接字符串
protected virtual async Task<string> ResolveConnectionStringAsync(
string connectionStringName)
{
// Multi-tenancy unaware contexts should always use the host connection string
if (typeof(TDbContext).IsDefined(typeof(IgnoreMultiTenancyAttribute), false))
{
using (CurrentTenant.Change(null))
{
return await ConnectionStringResolver.ResolveAsync(connectionStringName);
}
}
return await ConnectionStringResolver.ResolveAsync(connectionStringName);
}
protected virtual CancellationToken GetCancellationToken(
CancellationToken preferredValue = default)
{
return CancellationTokenProvider.FallbackToProvider(preferredValue);
}
}
并发标记的配置
public static void ConfigureConcurrencyStamp<T>(this EntityTypeBuilder<T> b)
where T : class, IHasConcurrencyStamp
{
b.As<EntityTypeBuilder>().TryConfigureConcurrencyStamp();
}
public static void TryConfigureConcurrencyStamp(this EntityTypeBuilder b)
{
if (b.Metadata.ClrType.IsAssignableTo<IHasConcurrencyStamp>())
{
b.Property(nameof(IHasConcurrencyStamp.ConcurrencyStamp))
.IsConcurrencyToken()
.HasMaxLength(ConcurrencyStampConsts.MaxLength)
.HasColumnName(nameof(IHasConcurrencyStamp.ConcurrencyStamp));
}
}
BasicRepositoryBase 仓储最基础的实现类
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Linq;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.Uow;
namespace Volo.Abp.Domain.Repositories;
//IUnitOfWorkEnabled 仓储本身方法是工作单元
public abstract class BasicRepositoryBase<TEntity> :
IBasicRepository<TEntity>,
IServiceProviderAccessor,
IUnitOfWorkEnabled
where TEntity : class, IEntity
{
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
public IServiceProvider ServiceProvider { get; set; }
public IDataFilter DataFilter =>
LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
public ICurrentTenant CurrentTenant =>
LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public IAsyncQueryableExecuter AsyncExecuter =>
LazyServiceProvider.LazyGetRequiredService<IAsyncQueryableExecuter>();
public IUnitOfWorkManager UnitOfWorkManager =>
LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
public ICancellationTokenProvider CancellationTokenProvider =>
LazyServiceProvider.LazyGetService<ICancellationTokenProvider>
(NullCancellationTokenProvider.Instance);
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);
}
}
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);
}
}
}
👍🎉🎊