refactor: ai+人工重构优化 framework

This commit is contained in:
橙子
2025-02-23 03:06:06 +08:00
parent f9341fd2ac
commit 3e07ca822a
61 changed files with 2604 additions and 1260 deletions

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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)
{
}

View File

@@ -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);
}
}

View File

@@ -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} 的备份操作尚未实现");
}
}
}

View File

@@ -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)!;
}
}

View File

@@ -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>

View File

@@ -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;

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}
}