😎增加视图初始化流程

This commit is contained in:
zuohuaijun 2025-05-19 02:08:46 +08:00
parent acb465ce57
commit ea917ec061
7 changed files with 166 additions and 0 deletions

View File

@ -27,6 +27,7 @@
//],
"DbSettings": {
"EnableInitDb": true, //
"EnableInitView": true, //
"EnableDiffLog": false, //
"EnableUnderLine": false, // 线
"EnableConnEncrypt": false // SM2

View File

@ -27,6 +27,7 @@
//],
"DbSettings": {
"EnableInitDb": true, //
"EnableInitView": true, //
"EnableDiffLog": false, //
"EnableUnderLine": false, // 线
"EnableConnEncrypt": false // SM2

View File

@ -0,0 +1,65 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Application.Entity;
/// <summary>
/// 用户表视图必须加IgnoreTable防止被生成为表
/// </summary>
[SugarTable(null, "用户表视图"), IgnoreTable]
public class TestViewSysUser : EntityBase, ISqlSugarView
{
/// <summary>
/// 账号
/// </summary>
[SugarColumn(ColumnDescription = "账号")]
public virtual string Account { get; set; }
/// <summary>
/// 真实姓名
/// </summary>
[SugarColumn(ColumnDescription = "真实姓名")]
public virtual string RealName { get; set; }
/// <summary>
/// 昵称
/// </summary>
[SugarColumn(ColumnDescription = "昵称")]
public string? NickName { get; set; }
/// <summary>
/// 机构名称
/// </summary>
[SugarColumn(ColumnDescription = "机构名称")]
public string? OrgName { get; set; }
/// <summary>
/// 职位名称
/// </summary>
[SugarColumn(ColumnDescription = "职位名称")]
public string? PosName { get; set; }
/// <summary>
/// 查询实例
/// </summary>
/// <param name="db"></param>
/// <returns></returns>
public string GetQueryableSqlString(SqlSugarScopeProvider db)
{
return db.Queryable<SysUser>()
.LeftJoin<SysOrg>((u, a) => u.OrgId == a.Id)
.LeftJoin<SysPos>((u, a, b) => u.PosId == b.Id)
.Select((u, a, b) => new TestViewSysUser
{
Id = u.Id,
Account = u.Account,
RealName = u.RealName,
NickName = u.NickName,
OrgName = a.Name,
PosName = b.Name,
}).ToMappedSqlString();
}
}

View File

@ -67,6 +67,11 @@ public sealed class DbSettings
/// </summary>
public bool EnableInitDb { get; set; }
/// <summary>
/// 启用视图初始化
/// </summary>
public bool EnableInitView { get; set; }
/// <summary>
/// 启用库表差异日志
/// </summary>

View File

@ -0,0 +1,20 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
namespace Admin.NET.Core;
/// <summary>
/// 视图实体接口
/// </summary>
public interface ISqlSugarView
{
/// <summary>
/// 获取视图查询sql语句
/// </summary>
/// <param name="db"></param>
/// <returns></returns>
public string GetQueryableSqlString(SqlSugarScopeProvider db);
}

View File

@ -463,4 +463,37 @@ public static class SqlSugarExtension
}
#endregion
#region
/// <summary>
/// 获取映射SQL语句, 用于创建视图
/// </summary>
/// <param name="queryable"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static string ToMappedSqlString<T>(this ISugarQueryable<T> queryable) where T : class
{
ArgumentNullException.ThrowIfNull(queryable);
// 获取实体映射信息
var entityInfo = queryable.Context.EntityMaintenance.GetEntityInfo(typeof(T));
if (entityInfo?.Columns == null || entityInfo.Columns.Count == 0) return queryable.ToSqlString();
// 构建需要替换的字段名映射(只处理实际有差异的字段)
var nameMap = entityInfo.Columns
.Where(c => !string.Equals(c.PropertyName, c.DbColumnName, StringComparison.OrdinalIgnoreCase))
.ToDictionary(k => k.PropertyName.ToLower(), v => v.DbColumnName, StringComparer.OrdinalIgnoreCase);
if (nameMap.Count == 0) return queryable.ToSqlString();
// 预编译正则表达式提升性能
var sql = queryable.ToSqlString();
foreach (var kv in nameMap)
{
sql = Regex.Replace(sql, $@"\b{kv.Key}\b", kv.Value ?? kv.Key, RegexOptions.IgnoreCase | RegexOptions.Compiled); // 单词边界匹配
}
return sql;
}
#endregion
}

View File

@ -406,6 +406,9 @@ public static class SqlSugarSetup
Task.WaitAll(taskList.ToArray());
}
// 初始化视图
if (config.DbSettings.EnableInitView || isFirstRun) InitView(dbProvider, config);
// 初始化种子数据
if (config.SeedSettings.EnableInitSeed || isFirstRun) InitSeedData(db, config);
@ -533,6 +536,44 @@ public static class SqlSugarSetup
}
}
/// <summary>
/// 初始化视图
/// </summary>
/// <param name="dbProvider"></param>
/// <param name="config"></param>
private static void InitView(SqlSugarScopeProvider dbProvider, DbConnectionConfig config)
{
Log.Information($"初始化视图 {config.DbType} - {config.ConfigId}");
var viewTypeList = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarView)))).ToList();
int taskIndex = 0, size = viewTypeList.Count;
var taskList = viewTypeList.Select(viewType => Task.Run(() =>
{
// 开始计时
var stopWatch = Stopwatch.StartNew();
// 获取视图实体和配置信息
var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(viewType) ?? throw new Exception("获取视图实体配置有误");
// 如果视图存在,则删除视图
if (dbProvider.DbMaintenance.GetViewInfoList().Any(it => it.Name.EqualIgnoreCase(entityInfo.DbTableName)))
dbProvider.DbMaintenance.DropView(entityInfo.DbTableName);
// 获取初始化视图查询SQL
var sql = viewType.GetMethod(nameof(ISqlSugarView.GetQueryableSqlString))?.Invoke(Activator.CreateInstance(viewType), [dbProvider]) as string;
if (string.IsNullOrWhiteSpace(sql)) throw new Exception("视图初始化Sql语句不能为空");
// 创建视图
dbProvider.Ado.ExecuteCommand($"CREATE VIEW {entityInfo.DbTableName} AS " + Environment.NewLine + " " + sql);
// 停止计时
stopWatch.Stop();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"初始化视图 {viewType.FullName,-58} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{size:D003},耗时:{stopWatch.ElapsedMilliseconds:N0} ms)");
}));
Task.WaitAll(taskList.ToArray());
}
/// <summary>
/// 初始化租户业务数据库
/// </summary>