using BaseOUDAL; using YLErp.Commons; namespace YLErp.Modules.AppModule.UpgradModule { /// /// 数据库结构及数据升级服务 /// public class DbUpdateService { const int UpState_Fail = -1; const int UpState_Done = 1; const int UpState_Pending = 0; const string UpType_DbUpdate = "DbUpdate"; const string ResNameSpacePrefix = "YLErp.Resources.DbUpdate.Ver"; #region----获取资源文件列表---- /// /// 获取资源文件列表 /// public static List GetUpdateList() { var upList = new List(); var assembly = typeof(YLErp.Resources.PlaceHolder).Assembly; foreach (var resName in assembly.GetManifestResourceNames()) { //YLErp.Resources.DbUpdate.Ver_3._17.prod.sql if (!resName.StartsWith(ResNameSpacePrefix)) { continue; } var upkey = resName.Substring(ResNameSpacePrefix.Length, resName.Length - ResNameSpacePrefix.Length - 4); var strArr = upkey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); var version = string.Join(".", strArr.Take(strArr.Length - 1).Select(n => n.Substring(1)).ToArray()); var dto = new DbUpdateDto { UpKey = upkey, Version = version, DbSchema = strArr[^1], UpResult = "未执行" }; upList.Add(dto); } var dic = GetLogs(); foreach (var dto in upList) { if (dic.TryGetValue(dto.UpKey, out var a)) { dto.UpState = a.UpState; dto.UpResult = a.UpResult; } } return upList.OrderByDescending(x => x.Version + ".").ThenBy(n => n.DbSchema).ToList(); } private static Dictionary GetLogs() { InnerDbLog[] getLogs(DbSet dbset) { var startDate = DateTime.Today.AddMonths(-6); var baseQry = from a in dbset where a.CreateTime > startDate && a.UpType == UpType_DbUpdate select a; var groupQry = from a in baseQry group a by a.UpKey into g select new { id = g.Max(n => n.id) }; var listQry = from g in groupQry join a in baseQry on g.id equals a.id select new InnerDbLog { UpKey = a.UpKey, UpResult = a.UpResult, UpState = a.UpState }; return listQry.ToArray(); } var list = new List(100); using (var db = DbContextFactory.GetYLDbContext()) { list.AddRange(getLogs(db.SysUpdateLogs)); } using (var db = DbContextFactory.GetErpBaseContext()) { list.AddRange(getLogs(db.SysUpdateLogs)); } using (var db = DbContextFactory.GetClientDbContext(OptUserInfo.SystemUser)) { list.AddRange(getLogs(db.SysUpdateLogs)); } return CollectionHelper.ToDictionary2(list, n => n.UpKey, n => n, StringComparer.OrdinalIgnoreCase, useFirst: true); } #endregion #region----执行数据库脚本升级---- /// /// 执行数据库脚本升级 /// public static List ExecuteUpdate(IEnumerable upKeyList, bool onlyUpdateDone) { var resultList = new List(); var exelist = upKeyList.OrderBy(n => n.ToLowerInvariant()).ToArray(); foreach (var upkey in exelist) { var result = InnerExecuteUpdate(upkey, onlyUpdateDone); resultList.Add(result); } return resultList; } /// /// 执行单个更新 /// private static DbUpdateResult InnerExecuteUpdate(string upkey, bool onlyUpdateDone) { var result = new DbUpdateResult { UpKey = upkey, UpState = UpState_Fail }; if (string.IsNullOrEmpty(upkey)) { result.UpResult = "upkey是空值"; return result; } result.UpState = UpState_Pending; var sqlText = string.Empty; if (onlyUpdateDone) { result.UpState = UpState_Done; result.UpResult = "手动更新为已执行"; } else { sqlText = GetResourceContent(upkey); if (sqlText == null) { result.UpState = UpState_Fail; result.UpResult = "没有找到升级脚本"; } else if (string.IsNullOrWhiteSpace(sqlText)) { sqlText = string.Empty; result.UpState = UpState_Done; result.UpResult = "升级脚本为空"; } } using (var db = getDbContext(upkey)) { if (db == null) { result.UpResult = "未从upkey中解析出正确的数据库"; return result; } if (result.UpState == UpState_Pending) { try { var changes = db.Database.ExecuteSqlRaw(sqlText); result.UpState = UpState_Done; result.UpResult = "执行成功,受影响的行数:" + changes; } catch (Exception ex) { result.UpState = UpState_Fail; result.UpResult = ex.Messages(); } } var dblog = new SysUpdateLog() { UpKey = upkey, UpType = UpType_DbUpdate, UpState = result.UpState, UpResult = result.UpResult, CreateTime = DateTime.Now }; db.SysUpdateLogs.Add(dblog); db.SaveChanges(); } return result; DBContextBase getDbContext(string upkey) { var index = upkey.LastIndexOf('.'); var dbSchema = upkey.Substring(index + 1); return (dbSchema?.ToLowerInvariant()) switch { "admin" => DbContextFactory.GetErpBaseContext(), "client" => DbContextFactory.GetClientDbContext(OptUserInfo.SystemUser), "prod" => DbContextFactory.GetYLDbContext(), _ => null, }; } } #endregion /// /// 查看数据库脚本升级内容 /// public static string GetUpdateContent(IEnumerable upKeyList) { if (upKeyList is null || !upKeyList.Any()) { return string.Empty; } var sb = StringBuilderPool.Acquire(); var exelist = upKeyList.OrderBy(n => { var index = n.LastIndexOf('.'); return n.Substring(0, index + 1); }).ToArray(); foreach (var upkey in exelist) { var sqlText = GetResourceContent(upkey); sb.AppendLine("-- -----------------------------------------------------------") .Append("-- V").Append(upkey.Replace("_", "")).AppendLine() .AppendLine("-- -----------------------------------------------------------"); if (sqlText == null) { sb.Append("-- !!!没有找到升级脚本:").Append(upkey).AppendLine(); } else { sb.AppendLine(sqlText); } } return sb.Release(); } /// /// 返回资源文件内容,如果是null表示资源不存在 /// private static string GetResourceContent(string upkey) { var resName = string.Concat(ResNameSpacePrefix, upkey, ".sql"); var assembly = typeof(Resources.PlaceHolder).Assembly; using var s = assembly.GetManifestResourceStream(resName); if (s == null) { return null; } using var sr = new StreamReader(s); return sr.ReadToEnd(); } class InnerDbLog { public string UpKey { get; set; } public string UpResult { get; set; } public int UpState { get; set; } } } }