增量更新表结构
/// <summary>
/// 初始化数据库
/// </summary>
/// <param name="db"></param>
/// <param name="config"></param>
private static void InitDatabase(SqlSugarScope db, DbConnectionConfig config)
{
SqlSugarScopeProvider dbProvider = db.GetConnectionScope(config.ConfigId);
// 兼容金仓
dbProvider.CurrentConnectionConfig.MoreSettings.DatabaseModel = SqlSugar.DbType.MySql;
dbProvider.CurrentConnectionConfig.MoreSettings.IsAutoToUpper = false;
dbProvider.CurrentConnectionConfig.MoreSettings.DisableNvarchar = true;
// 初始化/创建数据库
if (config.DbSettings.EnableInitDb)
{
Console.WriteLine($"初始化数据库 {config.DbType} - {config.ConfigId} - {config.ConnectionString}");
if (config.DbType != SqlSugar.DbType.Oracle)
dbProvider.DbMaintenance.CreateDatabase();
}
// 初始化表结构
if (config.TableSettings.EnableInitTable)
{
Console.WriteLine($"初始化表结构 {config.DbType} - {config.ConfigId}");
var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false))
.Where(u => !u.GetCustomAttributes<IgnoreTableAttribute>().Any())
.WhereIF(config.TableSettings.EnableIncreTable, u => u.IsDefined(typeof(IncreTableAttribute), false)).ToList();
if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) // 默认库(有系统表特性、没有日志表和租户表特性)
entityTypes = entityTypes.Where(u => u.GetCustomAttributes<SysTableAttribute>().Any() || (!u.GetCustomAttributes<LogTableAttribute>().Any() && !u.GetCustomAttributes<TenantAttribute>().Any())).ToList();
else if (config.ConfigId.ToString() == SqlSugarConst.LogConfigId) // 日志库
entityTypes = entityTypes.Where(u => u.GetCustomAttributes<LogTableAttribute>().Any()).ToList();
else
entityTypes = entityTypes.Where(u => u.GetCustomAttribute<TenantAttribute>()?.configId.ToString() == config.ConfigId.ToString()).ToList(); // 自定义的库
// 按是否分表分组,减少循环内反射开销
var splitTypes = new List<Type>(); // 分表: 按时间等把同一张表分成多张表,物理级别的
var normalTypes = new List<Type>(entityTypes.Count); // 普通表
foreach (var t in entityTypes)
{
if (t.GetCustomAttribute<SplitTableAttribute>() != null)
splitTypes.Add(t);
else
normalTypes.Add(t);
}
// 预检查:获取数据库中现有表名集合(忽略大小写)
var dbTableNames = new HashSet<string>(
dbProvider.DbMaintenance.GetTableInfoList(false).Select(t => t.Name),
StringComparer.OrdinalIgnoreCase);
// 获取所有实体信息,避免重复反射
var entityInfos = normalTypes.Select(t => new { Type = t, Info = dbProvider.EntityMaintenance.GetEntityInfo(t) }).ToList();
// 缓存数据库中已存在表的字段信息(表名->字段名集合,忽略大小写)
var dbTableColumnMap = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
foreach (var item in entityInfos)
{
var tableName = item.Info.DbTableName;
if (string.IsNullOrEmpty(tableName) || !dbTableNames.Contains(tableName))
continue;
if (!dbTableColumnMap.ContainsKey(tableName))
{
dbTableColumnMap[tableName] = new HashSet<string>(
dbProvider.DbMaintenance.GetColumnInfosByTableName(tableName).Select(c => c.DbColumnName),
StringComparer.OrdinalIgnoreCase);
}
}
// 筛选需要初始化的表:表不存在 或 字段缺失
var needTypes = entityInfos
.Where(item =>
{
var tableName = item.Info.DbTableName;
// 表不存在于数据库中 -> 需要初始化
if (string.IsNullOrEmpty(tableName) || !dbTableNames.Contains(tableName))
return true;
// 字段信息未获取到 -> 默认需要初始化
if (!dbTableColumnMap.TryGetValue(tableName, out var dbColumns))
return true;
// 存在实体字段不在数据库中 -> 需要初始化 (排除导航属性和已忽略列)
return item.Info.Columns.Any(c =>
c.Navigat == null && // 排除导航属性
!c.IsIgnore && // 排除已忽略的列
!string.IsNullOrEmpty(c.DbColumnName) &&
!dbColumns.Contains(c.DbColumnName));
})
.Select(item => item.Type)
.ToList();
int count = 0, sum = needTypes.Count;
foreach (var entityType in needTypes)
{
Console.WriteLine($"表变更 {entityType} ({++count}/{sum})");
if (entityType.GetCustomAttribute<SplitTableAttribute>() == null)
dbProvider.CodeFirst.InitTables(entityType);
}
// 批量创建 dbProvider.CodeFirst.InitTables(needTypes.ToArray());
// 分表仍需逐个创建(SqlSugar 分表 API 不支持批量数组)
count = 0; sum = splitTypes.Count;
foreach (var entityType in splitTypes)
{
Console.WriteLine($"分表变更 {entityType} ({++count}/{sum})");
dbProvider.CodeFirst.SplitTables().InitTables(entityType);
}
}
// 初始化种子数据
if (config.SeedSettings.EnableInitSeed)
{
_isHandlingSeedData = true;
Console.WriteLine($"初始化种子数据 {config.DbType} - {config.ConfigId}");
var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))))
.WhereIF(config.SeedSettings.EnableIncreSeed, u => u.IsDefined(typeof(IncreSeedAttribute), false))
.OrderBy(u => u.GetCustomAttributes(typeof(SeedDataAttribute), false).Length > 0 ? ((SeedDataAttribute)u.GetCustomAttributes(typeof(SeedDataAttribute), false)[0]).Order : 0).ToList();
int count = 0, sum = seedDataTypes.Count;
foreach (var seedType in seedDataTypes)
{
var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();
if (config.ConfigId.ToString() == SqlSugarConst.MainConfigId) // 默认库(有系统表特性、没有日志表和租户表特性)
{
if (entityType.GetCustomAttribute<SysTableAttribute>() == null && (entityType.GetCustomAttribute<LogTableAttribute>() != null || entityType.GetCustomAttribute<TenantAttribute>() != null))
continue;
}
else if (config.ConfigId.ToString() == SqlSugarConst.LogConfigId) // 日志库
{
if (entityType.GetCustomAttribute<LogTableAttribute>() == null)
continue;
}
else
{
var att = entityType.GetCustomAttribute<TenantAttribute>(); // 自定义的库
if (att == null || att.configId.ToString() != config.ConfigId.ToString()) continue;
}
var instance = Activator.CreateInstance(seedType);
var hasDataMethod = seedType.GetMethod("HasData");
var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>();
if (seedData == null) continue;
var entityInfo = dbProvider.EntityMaintenance.GetEntityInfo(entityType);
if (entityType.GetCustomAttribute<SplitTableAttribute>(true) != null)
{
//拆分表的操作需要实体类型,而通过反射很难实现
//所以,这里将Init方法写在“种子数据类”内部,再传入 db 反射调用
var hasInitMethod = seedType.GetMethod("Init");
var parameters = new object[] { db };
hasInitMethod?.Invoke(instance, parameters);
}
else
{
if (entityInfo.Columns.Any(u => u.IsPrimarykey))
{
// 按主键进行批量增加和更新
var storage = dbProvider.StorageableByObject(seedData.ToList()).ToStorage();
// 先修改再插入,否则会更新修改时间字段
if (seedType.GetCustomAttribute<IgnoreUpdateSeedAttribute>() == null) // 有忽略更新种子特性时则不更新
{
int updateCount = storage.AsUpdateable.IgnoreColumns(entityInfo.Columns.Where(u => u.PropertyInfo.GetCustomAttribute<IgnoreUpdateSeedColumnAttribute>() != null).Select(u => u.PropertyName).ToArray()).ExecuteCommand();
Console.WriteLine($" 修改 {updateCount}/{seedData.Count()} 条记录");
}
int insertCount = storage.AsInsertable.ExecuteCommand();
if (insertCount > 0)
{
Console.WriteLine($"添加数据 {entityInfo.DbTableName} ({++count}/{sum},种子数据:{seedData.Count()}) 插入 {insertCount} 条记录");
}
}
else
{
// 无主键则只进行插入
if (!dbProvider.Queryable(entityInfo.DbTableName, entityInfo.DbTableName).Any())
dbProvider.InsertableByObject(seedData.ToList()).ExecuteCommand();
}
}
}
_isHandlingSeedData = false;
}
}

1万+

被折叠的 条评论
为什么被折叠?



