refactor: ai+人工重构优化 framework
This commit is contained in:
@@ -2,18 +2,34 @@
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore
|
||||
{
|
||||
public class AsyncLocalDbContextAccessor
|
||||
/// <summary>
|
||||
/// 异步本地数据库上下文访问器
|
||||
/// 用于在异步流中保存和访问数据库上下文
|
||||
/// </summary>
|
||||
public sealed class AsyncLocalDbContextAccessor
|
||||
{
|
||||
private readonly AsyncLocal<ISqlSugarDbContext?> _currentScope;
|
||||
|
||||
/// <summary>
|
||||
/// 获取单例实例
|
||||
/// </summary>
|
||||
public static AsyncLocalDbContextAccessor Instance { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当前数据库上下文
|
||||
/// </summary>
|
||||
public ISqlSugarDbContext? Current
|
||||
{
|
||||
get => _currentScope.Value;
|
||||
set => _currentScope.Value = value;
|
||||
}
|
||||
public AsyncLocalDbContextAccessor()
|
||||
|
||||
/// <summary>
|
||||
/// 初始化异步本地数据库上下文访问器
|
||||
/// </summary>
|
||||
private AsyncLocalDbContextAccessor()
|
||||
{
|
||||
_currentScope = new AsyncLocal<ISqlSugarDbContext?>();
|
||||
}
|
||||
private readonly AsyncLocal<ISqlSugarDbContext> _currentScope;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,218 +18,233 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore;
|
||||
|
||||
/// <summary>
|
||||
/// 默认SqlSugar数据库上下文实现
|
||||
/// </summary>
|
||||
public class DefaultSqlSugarDbContext : SqlSugarDbContext
|
||||
{
|
||||
protected DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
|
||||
protected IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
|
||||
protected ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
|
||||
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||
protected IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
|
||||
public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
|
||||
protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
|
||||
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
|
||||
#region Protected Properties
|
||||
|
||||
protected IEntityChangeEventHelper EntityChangeEventHelper =>
|
||||
/// <summary>
|
||||
/// 数据库连接配置选项
|
||||
/// </summary>
|
||||
protected DbConnOptions DbOptions => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
|
||||
/// <summary>
|
||||
/// 当前用户服务
|
||||
/// </summary>
|
||||
protected ICurrentUser CurrentUserService => LazyServiceProvider.GetRequiredService<ICurrentUser>();
|
||||
|
||||
/// <summary>
|
||||
/// GUID生成器
|
||||
/// </summary>
|
||||
protected IGuidGenerator GuidGeneratorService => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
|
||||
|
||||
/// <summary>
|
||||
/// 日志工厂
|
||||
/// </summary>
|
||||
protected ILoggerFactory LoggerFactory => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
|
||||
|
||||
/// <summary>
|
||||
/// 当前租户服务
|
||||
/// </summary>
|
||||
protected ICurrentTenant CurrentTenantService => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||
|
||||
/// <summary>
|
||||
/// 数据过滤服务
|
||||
/// </summary>
|
||||
protected IDataFilter DataFilterService => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
|
||||
|
||||
/// <summary>
|
||||
/// 工作单元管理器
|
||||
/// </summary>
|
||||
protected IUnitOfWorkManager UnitOfWorkManagerService => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
|
||||
|
||||
/// <summary>
|
||||
/// 实体变更事件帮助类
|
||||
/// </summary>
|
||||
protected IEntityChangeEventHelper EntityChangeEventHelperService =>
|
||||
LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
|
||||
|
||||
public DefaultSqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
||||
/// <summary>
|
||||
/// 是否启用多租户过滤
|
||||
/// </summary>
|
||||
protected virtual bool IsMultiTenantFilterEnabled => DataFilterService?.IsEnabled<IMultiTenant>() ?? false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用软删除过滤
|
||||
/// </summary>
|
||||
protected virtual bool IsSoftDeleteFilterEnabled => DataFilterService?.IsEnabled<ISoftDelete>() ?? false;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public DefaultSqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
|
||||
: base(lazyServiceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义数据过滤器
|
||||
/// </summary>
|
||||
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
||||
{
|
||||
// 配置软删除过滤器
|
||||
if (IsSoftDeleteFilterEnabled)
|
||||
{
|
||||
sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false);
|
||||
sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(entity => !entity.IsDeleted);
|
||||
}
|
||||
|
||||
// 配置多租户过滤器
|
||||
if (IsMultiTenantFilterEnabled)
|
||||
{
|
||||
//表达式里只能有具体值,不能运算
|
||||
var expressionCurrentTenant = CurrentTenant.Id ?? null;
|
||||
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == expressionCurrentTenant);
|
||||
var currentTenantId = CurrentTenantService.Id;
|
||||
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(entity => entity.TenantId == currentTenantId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据执行前的处理
|
||||
/// </summary>
|
||||
public override void DataExecuting(object oldValue, DataFilterModel entityInfo)
|
||||
{
|
||||
//审计日志
|
||||
HandleAuditFields(oldValue, entityInfo);
|
||||
HandleEntityEvents(entityInfo);
|
||||
HandleDomainEvents(entityInfo);
|
||||
}
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// 处理审计字段
|
||||
/// </summary>
|
||||
private void HandleAuditFields(object oldValue, DataFilterModel entityInfo)
|
||||
{
|
||||
switch (entityInfo.OperationType)
|
||||
{
|
||||
case DataFilterType.UpdateByObject:
|
||||
|
||||
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
|
||||
{
|
||||
//最后更新时间,已经是最小值,忽略
|
||||
if (DateTime.MinValue.Equals(oldValue))
|
||||
{
|
||||
entityInfo.SetValue(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
entityInfo.SetValue(DateTime.Now);
|
||||
}
|
||||
}
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
|
||||
{
|
||||
if (typeof(Guid?) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||
{
|
||||
//最后更新者,已经是空guid,忽略
|
||||
if (Guid.Empty.Equals(oldValue))
|
||||
{
|
||||
entityInfo.SetValue(null);
|
||||
}
|
||||
else if (CurrentUser.Id != null)
|
||||
{
|
||||
entityInfo.SetValue(CurrentUser.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HandleUpdateAuditFields(oldValue, entityInfo);
|
||||
break;
|
||||
case DataFilterType.InsertByObject:
|
||||
|
||||
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
|
||||
{
|
||||
//类型为guid
|
||||
if (typeof(Guid) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||
{
|
||||
//主键为空或者为默认最小值
|
||||
if (Guid.Empty.Equals(oldValue))
|
||||
{
|
||||
entityInfo.SetValue(GuidGenerator.Create());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
|
||||
{
|
||||
//为空或者为默认最小值
|
||||
if (DateTime.MinValue.Equals(oldValue))
|
||||
{
|
||||
entityInfo.SetValue(DateTime.Now);
|
||||
}
|
||||
}
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
|
||||
{
|
||||
//类型为guid
|
||||
if (typeof(Guid?) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||
{
|
||||
if (CurrentUser.Id is not null)
|
||||
{
|
||||
entityInfo.SetValue(CurrentUser.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
|
||||
{
|
||||
if (CurrentTenant.Id is not null)
|
||||
{
|
||||
entityInfo.SetValue(CurrentTenant.Id);
|
||||
}
|
||||
}
|
||||
|
||||
HandleInsertAuditFields(oldValue, entityInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理更新时的审计字段
|
||||
/// </summary>
|
||||
private void HandleUpdateAuditFields(object oldValue, DataFilterModel entityInfo)
|
||||
{
|
||||
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
|
||||
{
|
||||
entityInfo.SetValue(DateTime.MinValue.Equals(oldValue) ? null : DateTime.Now);
|
||||
}
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId))
|
||||
&& entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(Guid?))
|
||||
{
|
||||
entityInfo.SetValue(Guid.Empty.Equals(oldValue) ? null : CurrentUserService.Id);
|
||||
}
|
||||
}
|
||||
|
||||
//实体变更领域事件
|
||||
/// <summary>
|
||||
/// 处理插入时的审计字段
|
||||
/// </summary>
|
||||
private void HandleInsertAuditFields(object oldValue, DataFilterModel entityInfo)
|
||||
{
|
||||
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
|
||||
{
|
||||
if (typeof(Guid) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||
{
|
||||
if (Guid.Empty.Equals(oldValue))
|
||||
{
|
||||
entityInfo.SetValue(GuidGeneratorService.Create());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
|
||||
{
|
||||
if (DateTime.MinValue.Equals(oldValue))
|
||||
{
|
||||
entityInfo.SetValue(DateTime.Now);
|
||||
}
|
||||
}
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
|
||||
{
|
||||
if (typeof(Guid?) == entityInfo.EntityColumnInfo.PropertyInfo.PropertyType)
|
||||
{
|
||||
if (CurrentUserService.Id is not null)
|
||||
{
|
||||
entityInfo.SetValue(CurrentUserService.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
|
||||
{
|
||||
if (CurrentTenantService.Id is not null)
|
||||
{
|
||||
entityInfo.SetValue(CurrentTenantService.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理实体变更事件
|
||||
/// </summary>
|
||||
private void HandleEntityEvents(DataFilterModel entityInfo)
|
||||
{
|
||||
// 实体变更领域事件
|
||||
switch (entityInfo.OperationType)
|
||||
{
|
||||
case DataFilterType.InsertByObject:
|
||||
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||
{
|
||||
EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue);
|
||||
EntityChangeEventHelperService.PublishEntityCreatedEvent(entityInfo.EntityValue);
|
||||
}
|
||||
|
||||
break;
|
||||
case DataFilterType.UpdateByObject:
|
||||
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||
{
|
||||
//软删除,发布的是删除事件
|
||||
if (entityInfo.EntityValue is ISoftDelete softDelete)
|
||||
{
|
||||
if (softDelete.IsDeleted == true)
|
||||
{
|
||||
EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
|
||||
EntityChangeEventHelperService.PublishEntityDeletedEvent(entityInfo.EntityValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue);
|
||||
EntityChangeEventHelperService.PublishEntityUpdatedEvent(entityInfo.EntityValue);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case DataFilterType.DeleteByObject:
|
||||
// if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||
// {
|
||||
//这里sqlsugar有个特殊,删除会返回批量的结果
|
||||
//这里sqlsugar有第二个特殊,删除事件是行级事件
|
||||
if (entityInfo.EntityValue is IEnumerable entityValues)
|
||||
if (entityInfo.EntityValue is IEnumerable entityValues)
|
||||
{
|
||||
foreach (var entityValue in entityValues)
|
||||
{
|
||||
foreach (var entityValue in entityValues)
|
||||
{
|
||||
EntityChangeEventHelper.PublishEntityDeletedEvent(entityValue);
|
||||
}
|
||||
EntityChangeEventHelperService.PublishEntityDeletedEvent(entityValue);
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//实体领域事件-所有操作类型
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理领域事件
|
||||
/// </summary>
|
||||
private void HandleDomainEvents(DataFilterModel entityInfo)
|
||||
{
|
||||
// 实体领域事件-所有操作类型
|
||||
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||
{
|
||||
var eventReport = CreateEventReport(entityInfo.EntityValue);
|
||||
var eventReport = CreateEventReport(entityInfo.EntityValue);
|
||||
PublishEntityEvents(eventReport);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLogExecuting(string sql, SugarParameter[] pars)
|
||||
{
|
||||
if (Options.EnabledSqlLog)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("==========Yi-SQL执行:==========");
|
||||
sb.AppendLine(UtilMethods.GetSqlString(DbType.SqlServer, sql, pars));
|
||||
sb.AppendLine("===============================");
|
||||
Logger.CreateLogger<DefaultSqlSugarDbContext>().LogDebug(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLogExecuted(string sql, SugarParameter[] pars)
|
||||
{
|
||||
if (Options.EnabledSqlLog)
|
||||
{
|
||||
var sqllog = $"=========Yi-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒=====";
|
||||
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sqllog.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override void EntityService(PropertyInfo propertyInfo, EntityColumnInfo entityColumnInfo)
|
||||
{
|
||||
if (propertyInfo.Name == nameof(IHasConcurrencyStamp.ConcurrencyStamp)) //带版本号并发更新
|
||||
{
|
||||
entityColumnInfo.IsEnableUpdateVersionValidation = true;
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType == typeof(ExtraPropertyDictionary))
|
||||
{
|
||||
entityColumnInfo.IsIgnore = true;
|
||||
}
|
||||
|
||||
if (propertyInfo.Name == nameof(Entity<object>.Id))
|
||||
{
|
||||
entityColumnInfo.IsPrimarykey = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建领域事件报告
|
||||
/// </summary>
|
||||
@@ -286,16 +301,58 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
|
||||
{
|
||||
foreach (var localEvent in changeReport.DomainEvents)
|
||||
{
|
||||
UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(
|
||||
UnitOfWorkManagerService.Current?.AddOrReplaceLocalEvent(
|
||||
new UnitOfWorkEventRecord(localEvent.EventData.GetType(), localEvent.EventData, localEvent.EventOrder)
|
||||
);
|
||||
}
|
||||
|
||||
foreach (var distributedEvent in changeReport.DistributedEvents)
|
||||
{
|
||||
UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(
|
||||
UnitOfWorkManagerService.Current?.AddOrReplaceDistributedEvent(
|
||||
new UnitOfWorkEventRecord(distributedEvent.EventData.GetType(), distributedEvent.EventData, distributedEvent.EventOrder)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void OnLogExecuting(string sql, SugarParameter[] pars)
|
||||
{
|
||||
if (DbOptions.EnabledSqlLog)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("==========Yi-SQL执行:==========");
|
||||
sb.AppendLine(UtilMethods.GetSqlString(DbType.SqlServer, sql, pars));
|
||||
sb.AppendLine("===============================");
|
||||
LoggerFactory.CreateLogger<DefaultSqlSugarDbContext>().LogDebug(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLogExecuted(string sql, SugarParameter[] pars)
|
||||
{
|
||||
if (DbOptions.EnabledSqlLog)
|
||||
{
|
||||
var sqllog = $"=========Yi-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒=====";
|
||||
LoggerFactory.CreateLogger<SqlSugarDbContext>().LogDebug(sqllog.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public override void EntityService(PropertyInfo propertyInfo, EntityColumnInfo entityColumnInfo)
|
||||
{
|
||||
if (propertyInfo.Name == nameof(IHasConcurrencyStamp.ConcurrencyStamp)) //带版本号并发更新
|
||||
{
|
||||
entityColumnInfo.IsEnableUpdateVersionValidation = true;
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType == typeof(ExtraPropertyDictionary))
|
||||
{
|
||||
entityColumnInfo.IsIgnore = true;
|
||||
}
|
||||
|
||||
if (propertyInfo.Name == nameof(Entity<object>.Id))
|
||||
{
|
||||
entityColumnInfo.IsPrimarykey = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,34 +21,39 @@ namespace Yi.Framework.SqlSugarCore.Repositories
|
||||
|
||||
public ISugarQueryable<TEntity> _DbQueryable => _Db.Queryable<TEntity>();
|
||||
|
||||
private ISugarDbContextProvider<ISqlSugarDbContext> _sugarDbContextProvider;
|
||||
private readonly ISugarDbContextProvider<ISqlSugarDbContext> _dbContextProvider;
|
||||
|
||||
/// <summary>
|
||||
/// 异步查询执行器
|
||||
/// </summary>
|
||||
public IAsyncQueryableExecuter AsyncExecuter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用变更追踪
|
||||
/// </summary>
|
||||
public bool? IsChangeTrackingEnabled => false;
|
||||
|
||||
public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider)
|
||||
public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> dbContextProvider)
|
||||
{
|
||||
_sugarDbContextProvider = sugarDbContextProvider;
|
||||
_dbContextProvider = dbContextProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取DB
|
||||
/// 获取数据库上下文
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<ISqlSugarClient> GetDbContextAsync()
|
||||
{
|
||||
var db = (await _sugarDbContextProvider.GetDbContextAsync()).SqlSugarClient;
|
||||
return db;
|
||||
var dbContext = await _dbContextProvider.GetDbContextAsync();
|
||||
return dbContext.SqlSugarClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取简单Db
|
||||
/// 获取简单数据库客户端
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<SimpleClient<TEntity>> GetDbSimpleClientAsync()
|
||||
{
|
||||
var db = await GetDbContextAsync();
|
||||
return new SimpleClient<TEntity>(db);
|
||||
var dbContext = await GetDbContextAsync();
|
||||
return new SimpleClient<TEntity>(dbContext);
|
||||
}
|
||||
|
||||
#region Abp模块
|
||||
@@ -166,7 +171,7 @@ namespace Yi.Framework.SqlSugarCore.Repositories
|
||||
{
|
||||
return (await GetDbSimpleClientAsync()).AsInsertable(insertObj);
|
||||
}
|
||||
|
||||
|
||||
public virtual async Task<IInsertable<TEntity>> AsInsertable(TEntity[] insertObjs)
|
||||
{
|
||||
return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs);
|
||||
|
||||
@@ -7,35 +7,47 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore
|
||||
namespace Yi.Framework.SqlSugarCore;
|
||||
|
||||
/// <summary>
|
||||
/// SqlSugar Core扩展方法
|
||||
/// </summary>
|
||||
public static class SqlSugarCoreExtensions
|
||||
{
|
||||
public static class SqlSugarCoreExtensions
|
||||
/// <summary>
|
||||
/// 添加数据库上下文
|
||||
/// </summary>
|
||||
/// <typeparam name="TDbContext">数据库上下文类型</typeparam>
|
||||
/// <param name="services">服务集合</param>
|
||||
/// <param name="serviceLifetime">服务生命周期</param>
|
||||
/// <returns>服务集合</returns>
|
||||
public static IServiceCollection AddYiDbContext<TDbContext>(
|
||||
this IServiceCollection services,
|
||||
ServiceLifetime serviceLifetime = ServiceLifetime.Transient)
|
||||
where TDbContext : class, ISqlSugarDbContextDependencies
|
||||
{
|
||||
/// <summary>
|
||||
/// 新增db对象,可支持多个
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
/// <param name="serviceLifetime"></param>
|
||||
/// <typeparam name="TDbContext"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddYiDbContext<TDbContext>(this IServiceCollection service, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where TDbContext : class, ISqlSugarDbContextDependencies
|
||||
{
|
||||
service.AddTransient<ISqlSugarDbContextDependencies, TDbContext>();
|
||||
return service;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增db对象,可支持多个
|
||||
/// </summary>
|
||||
/// <param name="service"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <typeparam name="TDbContext"></typeparam>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddYiDbContext<TDbContext>(this IServiceCollection service, Action<DbConnOptions> options) where TDbContext : class, ISqlSugarDbContextDependencies
|
||||
{
|
||||
service.Configure<DbConnOptions>(options.Invoke);
|
||||
service.AddYiDbContext<TDbContext>();
|
||||
return service;
|
||||
}
|
||||
services.TryAdd(new ServiceDescriptor(
|
||||
typeof(ISqlSugarDbContextDependencies),
|
||||
typeof(TDbContext),
|
||||
serviceLifetime));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加数据库上下文并配置选项
|
||||
/// </summary>
|
||||
/// <typeparam name="TDbContext">数据库上下文类型</typeparam>
|
||||
/// <param name="services">服务集合</param>
|
||||
/// <param name="configureOptions">配置选项委托</param>
|
||||
/// <returns>服务集合</returns>
|
||||
public static IServiceCollection AddYiDbContext<TDbContext>(
|
||||
this IServiceCollection services,
|
||||
Action<DbConnOptions> configureOptions)
|
||||
where TDbContext : class, ISqlSugarDbContextDependencies
|
||||
{
|
||||
services.Configure(configureOptions);
|
||||
services.AddYiDbContext<TDbContext>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,44 +5,78 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore;
|
||||
|
||||
/// <summary>
|
||||
/// SqlSugar数据库上下文基类
|
||||
/// </summary>
|
||||
public abstract class SqlSugarDbContext : ISqlSugarDbContextDependencies
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务提供者
|
||||
/// </summary>
|
||||
protected IAbpLazyServiceProvider LazyServiceProvider { get; }
|
||||
|
||||
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
|
||||
/// <summary>
|
||||
/// 数据库客户端实例
|
||||
/// </summary>
|
||||
protected ISqlSugarClient SqlSugarClient { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 执行顺序
|
||||
/// </summary>
|
||||
public virtual int ExecutionOrder => 0;
|
||||
|
||||
protected SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
|
||||
{
|
||||
this.LazyServiceProvider = lazyServiceProvider;
|
||||
LazyServiceProvider = lazyServiceProvider;
|
||||
}
|
||||
|
||||
|
||||
protected ISqlSugarClient SqlSugarClient { get;private set; }
|
||||
public int ExecutionOrder => 0;
|
||||
|
||||
public void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
|
||||
/// <summary>
|
||||
/// 配置SqlSugar客户端
|
||||
/// </summary>
|
||||
public virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
|
||||
{
|
||||
SqlSugarClient = sqlSugarClient;
|
||||
CustomDataFilter(sqlSugarClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义数据过滤器
|
||||
/// </summary>
|
||||
protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 数据执行后事件
|
||||
/// </summary>
|
||||
public virtual void DataExecuted(object oldValue, DataAfterModel entityInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据执行前事件
|
||||
/// </summary>
|
||||
public virtual void DataExecuting(object oldValue, DataFilterModel entityInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL执行前事件
|
||||
/// </summary>
|
||||
public virtual void OnLogExecuting(string sql, SugarParameter[] pars)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SQL执行后事件
|
||||
/// </summary>
|
||||
public virtual void OnLogExecuted(string sql, SugarParameter[] pars)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实体服务配置
|
||||
/// </summary>
|
||||
public virtual void EntityService(PropertyInfo propertyInfo, EntityColumnInfo entityColumnInfo)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -4,26 +4,52 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore;
|
||||
|
||||
/// <summary>
|
||||
/// SqlSugar数据库上下文创建上下文
|
||||
/// </summary>
|
||||
public class SqlSugarDbContextCreationContext
|
||||
{
|
||||
public static SqlSugarDbContextCreationContext Current => _current.Value;
|
||||
private static readonly AsyncLocal<SqlSugarDbContextCreationContext> _current = new AsyncLocal<SqlSugarDbContextCreationContext>();
|
||||
private static readonly AsyncLocal<SqlSugarDbContextCreationContext> CurrentContextHolder =
|
||||
new AsyncLocal<SqlSugarDbContextCreationContext>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前上下文
|
||||
/// </summary>
|
||||
public static SqlSugarDbContextCreationContext Current => CurrentContextHolder.Value!;
|
||||
|
||||
/// <summary>
|
||||
/// 连接字符串名称
|
||||
/// </summary>
|
||||
public string ConnectionStringName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接字符串
|
||||
/// </summary>
|
||||
public string ConnectionString { get; }
|
||||
|
||||
public DbConnection ExistingConnection { get; internal set; }
|
||||
/// <summary>
|
||||
/// 现有数据库连接
|
||||
/// </summary>
|
||||
public DbConnection? ExistingConnection { get; internal set; }
|
||||
|
||||
public SqlSugarDbContextCreationContext(string connectionStringName, string connectionString)
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public SqlSugarDbContextCreationContext(
|
||||
string connectionStringName,
|
||||
string connectionString)
|
||||
{
|
||||
ConnectionStringName = connectionStringName;
|
||||
ConnectionString = connectionString;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用指定的上下文
|
||||
/// </summary>
|
||||
public static IDisposable Use(SqlSugarDbContextCreationContext context)
|
||||
{
|
||||
var previousValue = Current;
|
||||
_current.Value = context;
|
||||
return new DisposeAction(() => _current.Value = previousValue);
|
||||
var previousContext = Current;
|
||||
CurrentContextHolder.Value = context;
|
||||
return new DisposeAction(() => CurrentContextHolder.Value = previousContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,189 +13,226 @@ using Check = Volo.Abp.Check;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlSugar数据库上下文工厂类
|
||||
/// 负责创建和配置SqlSugar客户端实例
|
||||
/// </summary>
|
||||
public class SqlSugarDbContextFactory : ISqlSugarDbContext
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// SqlSugar 客户端
|
||||
/// SqlSugar客户端实例
|
||||
/// </summary>
|
||||
public ISqlSugarClient SqlSugarClient { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 延迟服务提供者
|
||||
/// </summary>
|
||||
private IAbpLazyServiceProvider LazyServiceProvider { get; }
|
||||
|
||||
private TenantConfigurationWrapper TenantConfigurationWrapper=> LazyServiceProvider.LazyGetRequiredService<TenantConfigurationWrapper>();
|
||||
private ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||
/// <summary>
|
||||
/// 租户配置包装器
|
||||
/// </summary>
|
||||
private TenantConfigurationWrapper TenantConfigurationWrapper =>
|
||||
LazyServiceProvider.LazyGetRequiredService<TenantConfigurationWrapper>();
|
||||
|
||||
private DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
/// <summary>
|
||||
/// 当前租户信息
|
||||
/// </summary>
|
||||
private ICurrentTenant CurrentTenant =>
|
||||
LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||
|
||||
private ISerializeService SerializeService => LazyServiceProvider.LazyGetRequiredService<ISerializeService>();
|
||||
/// <summary>
|
||||
/// 数据库连接配置选项
|
||||
/// </summary>
|
||||
private DbConnOptions DbConnectionOptions =>
|
||||
LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
|
||||
/// <summary>
|
||||
/// 序列化服务
|
||||
/// </summary>
|
||||
private ISerializeService SerializeService =>
|
||||
LazyServiceProvider.LazyGetRequiredService<ISerializeService>();
|
||||
|
||||
/// <summary>
|
||||
/// SqlSugar上下文依赖项集合
|
||||
/// </summary>
|
||||
private IEnumerable<ISqlSugarDbContextDependencies> SqlSugarDbContextDependencies =>
|
||||
LazyServiceProvider.LazyGetRequiredService<IEnumerable<ISqlSugarDbContextDependencies>>();
|
||||
|
||||
/// <summary>
|
||||
/// 连接配置缓存字典
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<string, ConnectionConfig> ConnectionConfigCache = new();
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="lazyServiceProvider">延迟服务提供者</param>
|
||||
public SqlSugarDbContextFactory(IAbpLazyServiceProvider lazyServiceProvider)
|
||||
{
|
||||
LazyServiceProvider = lazyServiceProvider;
|
||||
|
||||
var tenantConfiguration= AsyncHelper.RunSync(async () =>await TenantConfigurationWrapper.GetAsync());
|
||||
// 异步获取租户配置
|
||||
var tenantConfiguration = AsyncHelper.RunSync(async () => await TenantConfigurationWrapper.GetAsync());
|
||||
|
||||
var connectionConfig =BuildConnectionConfig(action: options =>
|
||||
// 构建数据库连接配置
|
||||
var connectionConfig = BuildConnectionConfig(options =>
|
||||
{
|
||||
options.ConnectionString =tenantConfiguration.GetCurrentConnectionString();
|
||||
options.ConnectionString = tenantConfiguration.GetCurrentConnectionString();
|
||||
options.DbType = GetCurrentDbType(tenantConfiguration.GetCurrentConnectionName());
|
||||
});
|
||||
SqlSugarClient = new SqlSugarClient(connectionConfig);
|
||||
//生命周期,以下都可以直接使用sqlsugardb了
|
||||
|
||||
// Aop及多租户连接字符串和类型,需要单独设置
|
||||
// Aop操作不能进行缓存
|
||||
SetDbAop(SqlSugarClient);
|
||||
// 创建SqlSugar客户端实例
|
||||
SqlSugarClient = new SqlSugarClient(connectionConfig);
|
||||
|
||||
// 配置数据库AOP
|
||||
ConfigureDbAop(SqlSugarClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建Aop-sqlsugaraop在多租户模式中,需单独设置
|
||||
/// 配置数据库AOP操作
|
||||
/// </summary>
|
||||
/// <param name="sqlSugarClient"></param>
|
||||
protected virtual void SetDbAop(ISqlSugarClient sqlSugarClient)
|
||||
/// <param name="sqlSugarClient">SqlSugar客户端实例</param>
|
||||
protected virtual void ConfigureDbAop(ISqlSugarClient sqlSugarClient)
|
||||
{
|
||||
//替换默认序列化器
|
||||
// 配置序列化服务
|
||||
sqlSugarClient.CurrentConnectionConfig.ConfigureExternalServices.SerializeService = SerializeService;
|
||||
|
||||
//将所有,ISqlSugarDbContextDependencies进行累加
|
||||
// 初始化AOP事件处理器
|
||||
Action<string, SugarParameter[]> onLogExecuting = null;
|
||||
Action<string, SugarParameter[]> onLogExecuted = null;
|
||||
Action<object, DataFilterModel> dataExecuting = null;
|
||||
Action<object, DataAfterModel> dataExecuted = null;
|
||||
Action<ISqlSugarClient> onSqlSugarClientConfig = null;
|
||||
Action<ISqlSugarClient> onClientConfig = null;
|
||||
|
||||
// 按执行顺序聚合所有依赖项的AOP处理器
|
||||
foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x => x.ExecutionOrder))
|
||||
{
|
||||
onLogExecuting += dependency.OnLogExecuting;
|
||||
onLogExecuted += dependency.OnLogExecuted;
|
||||
dataExecuting += dependency.DataExecuting;
|
||||
dataExecuted += dependency.DataExecuted;
|
||||
|
||||
onSqlSugarClientConfig += dependency.OnSqlSugarClientConfig;
|
||||
onClientConfig += dependency.OnSqlSugarClientConfig;
|
||||
}
|
||||
|
||||
//最先存放db操作
|
||||
onSqlSugarClientConfig(sqlSugarClient);
|
||||
// 配置SqlSugar客户端
|
||||
onClientConfig?.Invoke(sqlSugarClient);
|
||||
|
||||
sqlSugarClient.Aop.OnLogExecuting =onLogExecuting;
|
||||
// 设置AOP事件
|
||||
sqlSugarClient.Aop.OnLogExecuting = onLogExecuting;
|
||||
sqlSugarClient.Aop.OnLogExecuted = onLogExecuted;
|
||||
|
||||
sqlSugarClient.Aop.DataExecuting =dataExecuting;
|
||||
sqlSugarClient.Aop.DataExecuted =dataExecuted;
|
||||
sqlSugarClient.Aop.DataExecuting = dataExecuting;
|
||||
sqlSugarClient.Aop.DataExecuted = dataExecuted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建连接配置
|
||||
/// 构建数据库连接配置
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
protected virtual ConnectionConfig BuildConnectionConfig(Action<ConnectionConfig>? action = null)
|
||||
/// <param name="configAction">配置操作委托</param>
|
||||
/// <returns>连接配置对象</returns>
|
||||
protected virtual ConnectionConfig BuildConnectionConfig(Action<ConnectionConfig> configAction = null)
|
||||
{
|
||||
var dbConnOptions = Options;
|
||||
|
||||
#region 组装options
|
||||
var dbConnOptions = DbConnectionOptions;
|
||||
|
||||
// 验证数据库类型配置
|
||||
if (dbConnOptions.DbType is null)
|
||||
{
|
||||
throw new ArgumentException("DbType配置为空");
|
||||
throw new ArgumentException("未配置数据库类型(DbType)");
|
||||
}
|
||||
|
||||
var slavaConFig = new List<SlaveConnectionConfig>();
|
||||
// 配置读写分离
|
||||
var slaveConfigs = new List<SlaveConnectionConfig>();
|
||||
if (dbConnOptions.EnabledReadWrite)
|
||||
{
|
||||
if (dbConnOptions.ReadUrl is null)
|
||||
{
|
||||
throw new ArgumentException("读写分离为空");
|
||||
throw new ArgumentException("启用读写分离但未配置读库连接字符串");
|
||||
}
|
||||
|
||||
var readCon = dbConnOptions.ReadUrl;
|
||||
|
||||
readCon.ForEach(s =>
|
||||
{
|
||||
//如果是动态saas分库,这里的连接串都不能写死,需要动态添加,这里只配置共享库的连接
|
||||
slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s });
|
||||
});
|
||||
slaveConfigs.AddRange(dbConnOptions.ReadUrl.Select(url =>
|
||||
new SlaveConnectionConfig { ConnectionString = url }));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 组装连接config
|
||||
|
||||
var connectionConfig = new ConnectionConfig()
|
||||
// 创建连接配置
|
||||
var connectionConfig = new ConnectionConfig
|
||||
{
|
||||
ConfigId = ConnectionStrings.DefaultConnectionStringName,
|
||||
DbType = dbConnOptions.DbType ?? DbType.Sqlite,
|
||||
ConnectionString = dbConnOptions.Url,
|
||||
IsAutoCloseConnection = true,
|
||||
SlaveConnectionConfigs = slavaConFig,
|
||||
//设置codefirst非空值判断
|
||||
ConfigureExternalServices = new ConfigureExternalServices
|
||||
{
|
||||
// 处理表
|
||||
EntityNameService = (type, entity) =>
|
||||
{
|
||||
if (dbConnOptions.EnableUnderLine && !entity.DbTableName.Contains('_'))
|
||||
entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName); // 驼峰转下划线
|
||||
},
|
||||
EntityService = (c, p) =>
|
||||
{
|
||||
if (new NullabilityInfoContext()
|
||||
.Create(c).WriteState is NullabilityState.Nullable)
|
||||
{
|
||||
p.IsNullable = true;
|
||||
}
|
||||
|
||||
if (dbConnOptions.EnableUnderLine && !p.IsIgnore && !p.DbColumnName.Contains('_'))
|
||||
p.DbColumnName = UtilMethods.ToUnderLine(p.DbColumnName); // 驼峰转下划线
|
||||
|
||||
//将所有,ISqlSugarDbContextDependencies的EntityService进行累加
|
||||
//额外的实体服务需要这里配置,
|
||||
|
||||
Action<PropertyInfo, EntityColumnInfo> entityService = null;
|
||||
foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x => x.ExecutionOrder))
|
||||
{
|
||||
entityService += dependency.EntityService;
|
||||
}
|
||||
|
||||
entityService(c, p);
|
||||
}
|
||||
},
|
||||
//这里多租户有个坑,这里配置是无效的
|
||||
// AopEvents = new AopEvents
|
||||
// {
|
||||
// DataExecuted = DataExecuted,
|
||||
// DataExecuting = DataExecuting,
|
||||
// OnLogExecuted = OnLogExecuted,
|
||||
// OnLogExecuting = OnLogExecuting
|
||||
// }
|
||||
SlaveConnectionConfigs = slaveConfigs,
|
||||
ConfigureExternalServices = CreateExternalServices(dbConnOptions)
|
||||
};
|
||||
|
||||
if (action is not null)
|
||||
{
|
||||
action.Invoke(connectionConfig);
|
||||
}
|
||||
|
||||
#endregion
|
||||
// 应用额外配置
|
||||
configAction?.Invoke(connectionConfig);
|
||||
|
||||
return connectionConfig;
|
||||
}
|
||||
|
||||
protected virtual DbType GetCurrentDbType(string tenantName)
|
||||
|
||||
/// <summary>
|
||||
/// 创建外部服务配置
|
||||
/// </summary>
|
||||
private ConfigureExternalServices CreateExternalServices(DbConnOptions dbConnOptions)
|
||||
{
|
||||
if (tenantName == ConnectionStrings.DefaultConnectionStringName)
|
||||
return new ConfigureExternalServices
|
||||
{
|
||||
return Options.DbType!.Value;
|
||||
}
|
||||
var dbTypeFromTenantName = GetDbTypeFromTenantName(tenantName);
|
||||
return dbTypeFromTenantName!.Value;
|
||||
EntityNameService = (type, entity) =>
|
||||
{
|
||||
if (dbConnOptions.EnableUnderLine && !entity.DbTableName.Contains('_'))
|
||||
{
|
||||
entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName);
|
||||
}
|
||||
},
|
||||
EntityService = (propertyInfo, columnInfo) =>
|
||||
{
|
||||
// 配置空值处理
|
||||
if (new NullabilityInfoContext().Create(propertyInfo).WriteState
|
||||
is NullabilityState.Nullable)
|
||||
{
|
||||
columnInfo.IsNullable = true;
|
||||
}
|
||||
|
||||
// 处理下划线命名
|
||||
if (dbConnOptions.EnableUnderLine && !columnInfo.IsIgnore
|
||||
&& !columnInfo.DbColumnName.Contains('_'))
|
||||
{
|
||||
columnInfo.DbColumnName = UtilMethods.ToUnderLine(columnInfo.DbColumnName);
|
||||
}
|
||||
|
||||
// 聚合所有依赖项的实体服务
|
||||
Action<PropertyInfo, EntityColumnInfo> entityService = null;
|
||||
foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x => x.ExecutionOrder))
|
||||
{
|
||||
entityService += dependency.EntityService;
|
||||
}
|
||||
|
||||
entityService?.Invoke(propertyInfo, columnInfo);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//根据租户name进行匹配db类型: Test@Sqlite,[form:AI]
|
||||
/// <summary>
|
||||
/// 获取当前数据库类型
|
||||
/// </summary>
|
||||
/// <param name="tenantName">租户名称</param>
|
||||
/// <returns>数据库类型</returns>
|
||||
protected virtual DbType GetCurrentDbType(string tenantName)
|
||||
{
|
||||
return tenantName == ConnectionStrings.DefaultConnectionStringName
|
||||
? DbConnectionOptions.DbType!.Value
|
||||
: GetDbTypeFromTenantName(tenantName)
|
||||
?? throw new ArgumentException($"无法从租户名称{tenantName}中解析数据库类型");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从租户名称解析数据库类型
|
||||
/// 格式:TenantName@DbType
|
||||
/// </summary>
|
||||
private DbType? GetDbTypeFromTenantName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
@@ -203,61 +240,50 @@ namespace Yi.Framework.SqlSugarCore
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查找@符号的位置
|
||||
int atIndex = name.LastIndexOf('@');
|
||||
|
||||
var atIndex = name.LastIndexOf('@');
|
||||
if (atIndex == -1 || atIndex == name.Length - 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 提取 枚举 部分
|
||||
string enumString = name.Substring(atIndex + 1);
|
||||
|
||||
// 尝试将 尾缀 转换为枚举
|
||||
if (Enum.TryParse<DbType>(enumString, out DbType result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"数据库{name}db类型错误或不支持:无法匹配{enumString}数据库类型");
|
||||
}
|
||||
var dbTypeString = name[(atIndex + 1)..];
|
||||
return Enum.TryParse<DbType>(dbTypeString, out var dbType)
|
||||
? dbType
|
||||
: throw new ArgumentException($"不支持的数据库类型: {dbTypeString}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 备份数据库
|
||||
/// </summary>
|
||||
public virtual void BackupDataBase()
|
||||
{
|
||||
string directoryName = "database_backup";
|
||||
string fileName = DateTime.Now.ToString($"yyyyMMdd_HHmmss") + $"_{SqlSugarClient.Ado.Connection.Database}";
|
||||
if (!Directory.Exists(directoryName))
|
||||
{
|
||||
Directory.CreateDirectory(directoryName);
|
||||
}
|
||||
const string backupDirectory = "database_backup";
|
||||
var fileName = $"{DateTime.Now:yyyyMMdd_HHmmss}_{SqlSugarClient.Ado.Connection.Database}";
|
||||
|
||||
Directory.CreateDirectory(backupDirectory);
|
||||
|
||||
switch (Options.DbType)
|
||||
switch (DbConnectionOptions.DbType)
|
||||
{
|
||||
case DbType.MySql:
|
||||
//MySql
|
||||
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
|
||||
$"{Path.Combine(directoryName, fileName)}.sql"); //mysql 只支持.net core
|
||||
SqlSugarClient.DbMaintenance.BackupDataBase(
|
||||
SqlSugarClient.Ado.Connection.Database,
|
||||
Path.Combine(backupDirectory, $"{fileName}.sql"));
|
||||
break;
|
||||
|
||||
|
||||
case DbType.Sqlite:
|
||||
//Sqlite
|
||||
SqlSugarClient.DbMaintenance.BackupDataBase(null, $"{fileName}.db"); //sqlite 只支持.net core
|
||||
SqlSugarClient.DbMaintenance.BackupDataBase(
|
||||
null,
|
||||
$"{fileName}.db");
|
||||
break;
|
||||
|
||||
|
||||
case DbType.SqlServer:
|
||||
//SqlServer
|
||||
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
|
||||
$"{Path.Combine(directoryName, fileName)}.bak" /*服务器路径*/); //第一个参数库名
|
||||
SqlSugarClient.DbMaintenance.BackupDataBase(
|
||||
SqlSugarClient.Ado.Connection.Database,
|
||||
Path.Combine(backupDirectory, $"{fileName}.bak"));
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new NotImplementedException("其他数据库备份未实现");
|
||||
throw new NotImplementedException($"数据库类型 {DbConnectionOptions.DbType} 的备份操作尚未实现");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,14 +63,14 @@ public class SqlSugarNonPublicSerializer : ISerializeService
|
||||
|
||||
// 调用 SerializeObject 方法序列化对象
|
||||
T json = (T)methods.MakeGenericMethod(typeof(T))
|
||||
.Invoke(null, new object[] { value, null });
|
||||
return json;
|
||||
.Invoke(null, new object[] { value, null! });
|
||||
return json!;
|
||||
}
|
||||
var jSetting = new JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
ContractResolver =new NonPublicPropertiesResolver() //替换默认解析器使能支持protect
|
||||
};
|
||||
return JsonConvert.DeserializeObject<T>(value, jSetting);
|
||||
return JsonConvert.DeserializeObject<T>(value, jSetting)!;
|
||||
}
|
||||
}
|
||||
@@ -7,56 +7,68 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
namespace Yi.Framework.SqlSugarCore;
|
||||
|
||||
/// <summary>
|
||||
/// 租户配置
|
||||
/// 租户配置包装器
|
||||
/// </summary>
|
||||
public class TenantConfigurationWrapper : ITransientDependency
|
||||
{
|
||||
private readonly IAbpLazyServiceProvider _serviceProvider;
|
||||
private ICurrentTenant CurrentTenant => _serviceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||
private ITenantStore TenantStore => _serviceProvider.LazyGetRequiredService<ITenantStore>();
|
||||
private DbConnOptions DbConnOptions => _serviceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
|
||||
private ICurrentTenant CurrentTenantService =>
|
||||
_serviceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||
|
||||
private ITenantStore TenantStoreService =>
|
||||
_serviceProvider.LazyGetRequiredService<ITenantStore>();
|
||||
|
||||
private DbConnOptions DbConnectionOptions =>
|
||||
_serviceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public TenantConfigurationWrapper(IAbpLazyServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取租户信息
|
||||
/// [from:ai]
|
||||
/// 获取租户配置信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<TenantConfiguration?> GetAsync()
|
||||
{
|
||||
//未开启多租户
|
||||
if (!DbConnOptions.EnabledSaasMultiTenancy)
|
||||
if (!DbConnectionOptions.EnabledSaasMultiTenancy)
|
||||
{
|
||||
return await TenantStore.FindAsync(ConnectionStrings.DefaultConnectionStringName);
|
||||
return await TenantStoreService.FindAsync(ConnectionStrings.DefaultConnectionStringName);
|
||||
}
|
||||
|
||||
TenantConfiguration? tenantConfiguration = null;
|
||||
|
||||
if (CurrentTenant.Id is not null)
|
||||
|
||||
return await GetTenantConfigurationByCurrentTenant();
|
||||
}
|
||||
|
||||
private async Task<TenantConfiguration?> GetTenantConfigurationByCurrentTenant()
|
||||
{
|
||||
// 通过租户ID查找
|
||||
if (CurrentTenantService.Id.HasValue)
|
||||
{
|
||||
tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Id.Value);
|
||||
if (tenantConfiguration == null)
|
||||
var config = await TenantStoreService.FindAsync(CurrentTenantService.Id.Value);
|
||||
if (config == null)
|
||||
{
|
||||
throw new ApplicationException($"未找到租户信息,租户Id:{CurrentTenant.Id}");
|
||||
throw new ApplicationException($"未找到租户信息,租户Id:{CurrentTenantService.Id}");
|
||||
}
|
||||
return tenantConfiguration;
|
||||
return config;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(CurrentTenant.Name))
|
||||
|
||||
// 通过租户名称查找
|
||||
if (!string.IsNullOrEmpty(CurrentTenantService.Name))
|
||||
{
|
||||
tenantConfiguration = await TenantStore.FindAsync(CurrentTenant.Name);
|
||||
if (tenantConfiguration == null)
|
||||
var config = await TenantStoreService.FindAsync(CurrentTenantService.Name);
|
||||
if (config == null)
|
||||
{
|
||||
throw new ApplicationException($"未找到租户信息,租户名称:{CurrentTenant.Name}");
|
||||
throw new ApplicationException($"未找到租户信息,租户名称:{CurrentTenantService.Name}");
|
||||
}
|
||||
return tenantConfiguration;
|
||||
return config;
|
||||
}
|
||||
|
||||
return await TenantStore.FindAsync(ConnectionStrings.DefaultConnectionStringName);
|
||||
|
||||
// 返回默认配置
|
||||
return await TenantStoreService.FindAsync(ConnectionStrings.DefaultConnectionStringName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,10 +8,20 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore.Uow
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlSugar数据库API实现
|
||||
/// </summary>
|
||||
public class SqlSugarDatabaseApi : IDatabaseApi
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库上下文
|
||||
/// </summary>
|
||||
public ISqlSugarDbContext DbContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化SqlSugar数据库API
|
||||
/// </summary>
|
||||
/// <param name="dbContext">数据库上下文</param>
|
||||
public SqlSugarDatabaseApi(ISqlSugarDbContext dbContext)
|
||||
{
|
||||
DbContext = dbContext;
|
||||
|
||||
@@ -3,33 +3,48 @@ using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore.Uow
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlSugar事务API实现
|
||||
/// </summary>
|
||||
public class SqlSugarTransactionApi : ITransactionApi, ISupportsRollback
|
||||
{
|
||||
private ISqlSugarDbContext _sqlsugarDbContext;
|
||||
private readonly ISqlSugarDbContext _dbContext;
|
||||
|
||||
public SqlSugarTransactionApi(ISqlSugarDbContext sqlsugarDbContext)
|
||||
public SqlSugarTransactionApi(ISqlSugarDbContext dbContext)
|
||||
{
|
||||
_sqlsugarDbContext = sqlsugarDbContext;
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库上下文
|
||||
/// </summary>
|
||||
public ISqlSugarDbContext GetDbContext()
|
||||
{
|
||||
return _sqlsugarDbContext;
|
||||
return _dbContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 提交事务
|
||||
/// </summary>
|
||||
public async Task CommitAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _sqlsugarDbContext.SqlSugarClient.Ado.CommitTranAsync();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sqlsugarDbContext.SqlSugarClient.Ado.Dispose();
|
||||
await _dbContext.SqlSugarClient.Ado.CommitTranAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回滚事务
|
||||
/// </summary>
|
||||
public async Task RollbackAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _sqlsugarDbContext.SqlSugarClient.Ado.RollbackTranAsync();
|
||||
await _dbContext.SqlSugarClient.Ado.RollbackTranAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_dbContext.SqlSugarClient.Ado.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,112 +13,121 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
||||
{
|
||||
public class UnitOfWorkSqlsugarDbContextProvider<TDbContext> : ISugarDbContextProvider<TDbContext> where TDbContext : ISqlSugarDbContext
|
||||
{
|
||||
/// <summary>
|
||||
/// 日志记录器
|
||||
/// </summary>
|
||||
public ILogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>> Logger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 服务提供者
|
||||
/// </summary>
|
||||
public IServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库上下文访问器实例
|
||||
/// </summary>
|
||||
private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance;
|
||||
protected readonly TenantConfigurationWrapper _tenantConfigurationWrapper;
|
||||
protected readonly IUnitOfWorkManager UnitOfWorkManager;
|
||||
protected readonly IConnectionStringResolver ConnectionStringResolver;
|
||||
protected readonly ICancellationTokenProvider CancellationTokenProvider;
|
||||
protected readonly ICurrentTenant CurrentTenant;
|
||||
|
||||
private readonly TenantConfigurationWrapper _tenantConfigurationWrapper;
|
||||
private readonly IUnitOfWorkManager _unitOfWorkManager;
|
||||
private readonly IConnectionStringResolver _connectionStringResolver;
|
||||
private readonly ICancellationTokenProvider _cancellationTokenProvider;
|
||||
private readonly ICurrentTenant _currentTenant;
|
||||
|
||||
public UnitOfWorkSqlsugarDbContextProvider(
|
||||
IUnitOfWorkManager unitOfWorkManager,
|
||||
IConnectionStringResolver connectionStringResolver,
|
||||
ICancellationTokenProvider cancellationTokenProvider,
|
||||
ICurrentTenant currentTenant, TenantConfigurationWrapper tenantConfigurationWrapper)
|
||||
ICurrentTenant currentTenant,
|
||||
TenantConfigurationWrapper tenantConfigurationWrapper)
|
||||
{
|
||||
UnitOfWorkManager = unitOfWorkManager;
|
||||
ConnectionStringResolver = connectionStringResolver;
|
||||
CancellationTokenProvider = cancellationTokenProvider;
|
||||
CurrentTenant = currentTenant;
|
||||
_unitOfWorkManager = unitOfWorkManager;
|
||||
_connectionStringResolver = connectionStringResolver;
|
||||
_cancellationTokenProvider = cancellationTokenProvider;
|
||||
_currentTenant = currentTenant;
|
||||
_tenantConfigurationWrapper = tenantConfigurationWrapper;
|
||||
Logger = NullLogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>>.Instance;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库上下文
|
||||
/// </summary>
|
||||
public virtual async Task<TDbContext> GetDbContextAsync()
|
||||
{
|
||||
//获取当前连接字符串,未多租户时,默认为空
|
||||
var tenantConfiguration= await _tenantConfigurationWrapper.GetAsync();
|
||||
//由于sqlsugar的特殊性,没有db区分,不再使用连接字符串解析器
|
||||
// 获取当前租户配置
|
||||
var tenantConfiguration = await _tenantConfigurationWrapper.GetAsync();
|
||||
|
||||
// 获取连接字符串信息
|
||||
var connectionStringName = tenantConfiguration.GetCurrentConnectionName();
|
||||
var connectionString = tenantConfiguration.GetCurrentConnectionString();
|
||||
var dbContextKey = $"{this.GetType().Name}_{connectionString}";
|
||||
|
||||
var unitOfWork = UnitOfWorkManager.Current;
|
||||
if (unitOfWork == null )
|
||||
{
|
||||
//var dbContext = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
|
||||
//如果不启用工作单元,创建一个新的db,不开启事务即可
|
||||
//return dbContext;
|
||||
|
||||
//2024-11-30,改回强制性使用工作单元,否则容易造成歧义
|
||||
throw new AbpException("DbContext 只能在工作单元内工作,当前DbContext没有工作单元,如需创建新线程并发操作,请手动创建工作单元");
|
||||
|
||||
var unitOfWork = _unitOfWorkManager.Current;
|
||||
if (unitOfWork == null)
|
||||
{
|
||||
throw new AbpException(
|
||||
"DbContext 只能在工作单元内工作,当前DbContext没有工作单元,如需创建新线程并发操作,请手动创建工作单元");
|
||||
}
|
||||
//尝试当前工作单元获取db
|
||||
|
||||
// 尝试从当前工作单元获取数据库API
|
||||
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
|
||||
|
||||
//当前没有db创建一个新的db
|
||||
// 当前没有数据库API则创建新的
|
||||
if (databaseApi == null)
|
||||
{
|
||||
//db根据连接字符串来创建
|
||||
databaseApi = new SqlSugarDatabaseApi(
|
||||
await CreateDbContextAsync(unitOfWork, connectionStringName, connectionString)
|
||||
await CreateDbContextAsync(unitOfWork, connectionStringName, connectionString)
|
||||
);
|
||||
//创建的db加入到当前工作单元中
|
||||
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
|
||||
|
||||
}
|
||||
|
||||
return (TDbContext)((SqlSugarDatabaseApi)databaseApi).DbContext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName, string connectionString)
|
||||
/// <summary>
|
||||
/// 创建数据库上下文
|
||||
/// </summary>
|
||||
protected virtual async Task<TDbContext> CreateDbContextAsync(
|
||||
IUnitOfWork unitOfWork,
|
||||
string connectionStringName,
|
||||
string connectionString)
|
||||
{
|
||||
var creationContext = new SqlSugarDbContextCreationContext(connectionStringName, connectionString);
|
||||
//将连接key进行传值
|
||||
using (SqlSugarDbContextCreationContext.Use(creationContext))
|
||||
{
|
||||
var dbContext = await CreateDbContextAsync(unitOfWork);
|
||||
return dbContext;
|
||||
return await CreateDbContextAsync(unitOfWork);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据工作单元创建数据库上下文
|
||||
/// </summary>
|
||||
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork)
|
||||
{
|
||||
return unitOfWork.Options.IsTransactional
|
||||
? await CreateDbContextWithTransactionAsync(unitOfWork)
|
||||
: unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建带事务的数据库上下文
|
||||
/// </summary>
|
||||
protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
|
||||
{
|
||||
//事务key
|
||||
var transactionApiKey = $"SqlSugarCore_{SqlSugarDbContextCreationContext.Current.ConnectionString}";
|
||||
|
||||
//尝试查找事务
|
||||
var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi;
|
||||
|
||||
//该db还没有进行开启事务
|
||||
if (activeTransaction == null)
|
||||
{
|
||||
//获取到db添加事务即可
|
||||
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
|
||||
var transaction = new SqlSugarTransactionApi(
|
||||
dbContext
|
||||
);
|
||||
var transaction = new SqlSugarTransactionApi(dbContext);
|
||||
unitOfWork.AddTransactionApi(transactionApiKey, transaction);
|
||||
|
||||
await dbContext.SqlSugarClient.Ado.BeginTranAsync();
|
||||
return dbContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (TDbContext)activeTransaction.GetDbContext();
|
||||
}
|
||||
|
||||
|
||||
return (TDbContext)activeTransaction.GetDbContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,142 +18,177 @@ using Yi.Framework.SqlSugarCore.Uow;
|
||||
|
||||
namespace Yi.Framework.SqlSugarCore
|
||||
{
|
||||
/// <summary>
|
||||
/// SqlSugar Core模块
|
||||
/// </summary>
|
||||
[DependsOn(typeof(AbpDddDomainModule))]
|
||||
public class YiFrameworkSqlSugarCoreModule : AbpModule
|
||||
{
|
||||
public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
|
||||
{
|
||||
var service = context.Services;
|
||||
var configuration = service.GetConfiguration();
|
||||
var services = context.Services;
|
||||
var configuration = services.GetConfiguration();
|
||||
|
||||
// 配置数据库连接选项
|
||||
ConfigureDbOptions(services, configuration);
|
||||
|
||||
// 配置GUID生成器
|
||||
ConfigureGuidGenerator(services);
|
||||
|
||||
// 注册仓储和服务
|
||||
RegisterRepositories(services);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void ConfigureDbOptions(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var section = configuration.GetSection("DbConnOptions");
|
||||
Configure<DbConnOptions>(section);
|
||||
|
||||
var dbConnOptions = new DbConnOptions();
|
||||
section.Bind(dbConnOptions);
|
||||
|
||||
//很多人遗漏了这一点,不同的数据库,对于主键的使用规约不一样,需要根据数据库进行判断
|
||||
SequentialGuidType guidType;
|
||||
switch (dbConnOptions.DbType)
|
||||
{
|
||||
case DbType.MySql:
|
||||
case DbType.PostgreSQL:
|
||||
guidType= SequentialGuidType.SequentialAsString;
|
||||
break;
|
||||
case DbType.SqlServer:
|
||||
guidType = SequentialGuidType.SequentialAtEnd;
|
||||
break;
|
||||
case DbType.Oracle:
|
||||
guidType = SequentialGuidType.SequentialAsBinary;
|
||||
break;
|
||||
default:
|
||||
guidType = SequentialGuidType.SequentialAtEnd;
|
||||
break;
|
||||
}
|
||||
// 配置默认连接字符串
|
||||
Configure<AbpDbConnectionOptions>(options =>
|
||||
{
|
||||
options.ConnectionStrings.Default = dbConnOptions.Url;
|
||||
});
|
||||
|
||||
// 配置默认租户
|
||||
ConfigureDefaultTenant(services, dbConnOptions);
|
||||
}
|
||||
|
||||
private void ConfigureGuidGenerator(IServiceCollection services)
|
||||
{
|
||||
var dbConnOptions = services.GetConfiguration()
|
||||
.GetSection("DbConnOptions")
|
||||
.Get<DbConnOptions>();
|
||||
|
||||
var guidType = GetSequentialGuidType(dbConnOptions?.DbType);
|
||||
Configure<AbpSequentialGuidGeneratorOptions>(options =>
|
||||
{
|
||||
options.DefaultSequentialGuidType = guidType;
|
||||
});
|
||||
|
||||
service.TryAddTransient<ISqlSugarDbContext, SqlSugarDbContextFactory>();
|
||||
|
||||
//不开放sqlsugarClient
|
||||
//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlsugarDbContext>().SqlSugarClient);
|
||||
|
||||
|
||||
service.AddTransient(typeof(IRepository<>), typeof(SqlSugarRepository<>));
|
||||
service.AddTransient(typeof(IRepository<,>), typeof(SqlSugarRepository<,>));
|
||||
service.AddTransient(typeof(ISqlSugarRepository<>), typeof(SqlSugarRepository<>));
|
||||
service.AddTransient(typeof(ISqlSugarRepository<,>), typeof(SqlSugarRepository<,>));
|
||||
|
||||
service.AddTransient(typeof(ISugarDbContextProvider<>), typeof(UnitOfWorkSqlsugarDbContextProvider<>));
|
||||
//替换Sqlsugar默认序列化器,用来解决.Select()不支持嵌套对象/匿名对象的非公有访问器 值无法绑定,如Id属性
|
||||
context.Services.AddSingleton<ISerializeService, SqlSugarNonPublicSerializer>();
|
||||
|
||||
var dbConfig = section.Get<DbConnOptions>();
|
||||
//将默认db传递给abp连接字符串模块
|
||||
Configure<AbpDbConnectionOptions>(x => { x.ConnectionStrings.Default = dbConfig.Url; });
|
||||
//配置abp默认租户,对接abp模块
|
||||
Configure<AbpDefaultTenantStoreOptions>(x => {
|
||||
var tenantList = x.Tenants.ToList();
|
||||
foreach(var tenant in tenantList)
|
||||
{
|
||||
tenant.NormalizedName = tenant.Name.Contains("@") ?
|
||||
tenant.Name.Substring(0, tenant.Name.LastIndexOf("@")) :
|
||||
tenant.Name;
|
||||
}
|
||||
tenantList.Insert(0, new TenantConfiguration
|
||||
{
|
||||
Id = Guid.Empty,
|
||||
Name = $"{ConnectionStrings.DefaultConnectionStringName}",
|
||||
NormalizedName = ConnectionStrings.DefaultConnectionStringName,
|
||||
ConnectionStrings = new ConnectionStrings() { { ConnectionStrings.DefaultConnectionStringName, dbConfig.Url } },
|
||||
IsActive = true
|
||||
});
|
||||
x.Tenants = tenantList.ToArray();
|
||||
});
|
||||
context.Services.AddYiDbContext<DefaultSqlSugarDbContext>();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void RegisterRepositories(IServiceCollection services)
|
||||
{
|
||||
services.TryAddTransient<ISqlSugarDbContext, SqlSugarDbContextFactory>();
|
||||
services.AddTransient(typeof(IRepository<>), typeof(SqlSugarRepository<>));
|
||||
services.AddTransient(typeof(IRepository<,>), typeof(SqlSugarRepository<,>));
|
||||
services.AddTransient(typeof(ISqlSugarRepository<>), typeof(SqlSugarRepository<>));
|
||||
services.AddTransient(typeof(ISqlSugarRepository<,>), typeof(SqlSugarRepository<,>));
|
||||
services.AddTransient(typeof(ISugarDbContextProvider<>), typeof(UnitOfWorkSqlsugarDbContextProvider<>));
|
||||
services.AddSingleton<ISerializeService, SqlSugarNonPublicSerializer>();
|
||||
services.AddYiDbContext<DefaultSqlSugarDbContext>();
|
||||
}
|
||||
|
||||
private void ConfigureDefaultTenant(IServiceCollection services, DbConnOptions dbConfig)
|
||||
{
|
||||
Configure<AbpDefaultTenantStoreOptions>(options =>
|
||||
{
|
||||
var tenants = options.Tenants.ToList();
|
||||
|
||||
// 规范化租户名称
|
||||
foreach (var tenant in tenants)
|
||||
{
|
||||
tenant.NormalizedName = tenant.Name.Contains("@")
|
||||
? tenant.Name.Substring(0, tenant.Name.LastIndexOf("@"))
|
||||
: tenant.Name;
|
||||
}
|
||||
|
||||
// 添加默认租户
|
||||
tenants.Insert(0, new TenantConfiguration
|
||||
{
|
||||
Id = Guid.Empty,
|
||||
Name = ConnectionStrings.DefaultConnectionStringName,
|
||||
NormalizedName = ConnectionStrings.DefaultConnectionStringName,
|
||||
ConnectionStrings = new ConnectionStrings
|
||||
{
|
||||
{ ConnectionStrings.DefaultConnectionStringName, dbConfig.Url }
|
||||
},
|
||||
IsActive = true
|
||||
});
|
||||
|
||||
options.Tenants = tenants.ToArray();
|
||||
});
|
||||
}
|
||||
|
||||
private SequentialGuidType GetSequentialGuidType(DbType? dbType)
|
||||
{
|
||||
return dbType switch
|
||||
{
|
||||
DbType.MySql or DbType.PostgreSQL => SequentialGuidType.SequentialAsString,
|
||||
DbType.SqlServer => SequentialGuidType.SequentialAtEnd,
|
||||
DbType.Oracle => SequentialGuidType.SequentialAsBinary,
|
||||
_ => SequentialGuidType.SequentialAtEnd
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||
{
|
||||
//进行CodeFirst
|
||||
var service = context.ServiceProvider;
|
||||
var options = service.GetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
var serviceProvider = context.ServiceProvider;
|
||||
var options = serviceProvider.GetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
var logger = serviceProvider.GetRequiredService<ILogger<YiFrameworkSqlSugarCoreModule>>();
|
||||
|
||||
var logger = service.GetRequiredService<ILogger<YiFrameworkSqlSugarCoreModule>>();
|
||||
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("==========Yi-SQL配置:==========");
|
||||
sb.AppendLine($"数据库连接字符串:{options.Url}");
|
||||
sb.AppendLine($"数据库类型:{options.DbType.ToString()}");
|
||||
sb.AppendLine($"是否开启种子数据:{options.EnabledDbSeed}");
|
||||
sb.AppendLine($"是否开启CodeFirst:{options.EnabledCodeFirst}");
|
||||
sb.AppendLine($"是否开启Saas多租户:{options.EnabledSaasMultiTenancy}");
|
||||
sb.AppendLine("===============================");
|
||||
|
||||
|
||||
logger.LogInformation(sb.ToString());
|
||||
// 记录配置信息
|
||||
LogConfiguration(logger, options);
|
||||
|
||||
// 初始化数据库
|
||||
if (options.EnabledCodeFirst)
|
||||
{
|
||||
CodeFirst(service);
|
||||
await InitializeDatabase(serviceProvider);
|
||||
}
|
||||
|
||||
// 初始化种子数据
|
||||
if (options.EnabledDbSeed)
|
||||
{
|
||||
await DataSeedAsync(service);
|
||||
await InitializeSeedData(serviceProvider);
|
||||
}
|
||||
}
|
||||
|
||||
private void CodeFirst(IServiceProvider service)
|
||||
private void LogConfiguration(ILogger logger, DbConnOptions options)
|
||||
{
|
||||
var moduleContainer = service.GetRequiredService<IModuleContainer>();
|
||||
var db = service.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient;
|
||||
var logMessage = new StringBuilder()
|
||||
.AppendLine()
|
||||
.AppendLine("==========Yi-SQL配置:==========")
|
||||
.AppendLine($"数据库连接字符串:{options.Url}")
|
||||
.AppendLine($"数据库类型:{options.DbType}")
|
||||
.AppendLine($"是否开启种子数据:{options.EnabledDbSeed}")
|
||||
.AppendLine($"是否开启CodeFirst:{options.EnabledCodeFirst}")
|
||||
.AppendLine($"是否开启Saas多租户:{options.EnabledSaasMultiTenancy}")
|
||||
.AppendLine("===============================")
|
||||
.ToString();
|
||||
|
||||
//尝试创建数据库
|
||||
logger.LogInformation(logMessage);
|
||||
}
|
||||
|
||||
private async Task InitializeDatabase(IServiceProvider serviceProvider)
|
||||
{
|
||||
var moduleContainer = serviceProvider.GetRequiredService<IModuleContainer>();
|
||||
var db = serviceProvider.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient;
|
||||
|
||||
// 创建数据库
|
||||
db.DbMaintenance.CreateDatabase();
|
||||
|
||||
List<Type> types = new List<Type>();
|
||||
foreach (var module in moduleContainer.Modules)
|
||||
{
|
||||
types.AddRange(module.Assembly.GetTypes()
|
||||
.Where(x => x.GetCustomAttribute<IgnoreCodeFirstAttribute>() == null)
|
||||
.Where(x => x.GetCustomAttribute<SugarTable>() != null)
|
||||
.Where(x => x.GetCustomAttribute<SplitTableAttribute>() is null));
|
||||
}
|
||||
// 获取需要创建表的实体类型
|
||||
var entityTypes = moduleContainer.Modules
|
||||
.SelectMany(m => m.Assembly.GetTypes())
|
||||
.Where(t => t.GetCustomAttribute<IgnoreCodeFirstAttribute>() == null
|
||||
&& t.GetCustomAttribute<SugarTable>() != null
|
||||
&& t.GetCustomAttribute<SplitTableAttribute>() == null)
|
||||
.ToList();
|
||||
|
||||
if (types.Count > 0)
|
||||
if (entityTypes.Any())
|
||||
{
|
||||
db.CopyNew().CodeFirst.InitTables(types.ToArray());
|
||||
db.CopyNew().CodeFirst.InitTables(entityTypes.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DataSeedAsync(IServiceProvider service)
|
||||
private async Task InitializeSeedData(IServiceProvider serviceProvider)
|
||||
{
|
||||
var dataSeeder = service.GetRequiredService<IDataSeeder>();
|
||||
var dataSeeder = serviceProvider.GetRequiredService<IDataSeeder>();
|
||||
await dataSeeder.SeedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user