# -*- coding: utf-8 -*- """触发器生成器重构:①去掉聚合用列引用模式 ②箱号表数量触发器按箱号行生成(WHEN 行ID,真 SUM) ③图号行触发器传箱号表 ④重建/新表入口同步。幂等。""" import io P = r"C:\Users\099978\Documents\SharpDevelop Projects\成套报价软件\成套报价软件\计算引擎.cs" s = io.open(P, encoding="utf-8-sig").read() n = 0 def rep(old, new): global s, n if new in s and old not in s: print("已改(跳过):", old[:50].replace("\n", " ")) return assert old in s, "锚点缺失: " + old[:80] s = s.replace(old, new, 1) n += 1 # 1) 子翻译 透传清理 rep("p.引用模式 = 引用模式; p.下层表 = 下层表; p.层内公式 = 层内公式; p.展开栈 = 展开栈; p.聚合用列引用 = 聚合用列引用;", "p.引用模式 = 引用模式; p.下层表 = 下层表; p.层内公式 = 层内公式; p.展开栈 = 展开栈;") # 2) 解析器删字段 rep(''' public string 引用模式 = "NEW"; // NEW=触发器 NEW."列" / ROW=上级目标行 "列" public bool 聚合用列引用 = false; // true=SUM('列') 直接引用本行列(该聚合由下级触发器维护)''', ''' public string 引用模式 = "NEW"; // NEW=触发器 NEW."列" / ROW=上级目标行 "列"''') # 3) Sum子查询 删分支 rep(''' /// SUM('列') → 对下层表整表求和;或(自触发场景)直接引用本行列(由下级触发器维护)。 private string Sum子查询(string col) { string c = "\\"" + col.Replace("\\"", "\\"\\"") + "\\""; if (聚合用列引用) return "COALESCE(CAST(" + (引用模式 == "NEW" ? "NEW." : "") + c + " AS REAL),0)"; return "COALESCE((SELECT CAST(SUM(CAST(" + c + " AS REAL)) AS REAL) FROM \\"" + 下层表.Replace("\\"", "\\"\\"") + "\\"),0)"; }''', ''' /// SUM('列') → 对下层表整表求和(每箱号一张元件表/每图号一张箱号表,无条件)。 private string Sum子查询(string col) { return "COALESCE((SELECT CAST(SUM(CAST(\\"" + col.Replace("\\"", "\\"\\"") + "\\" AS REAL)) AS REAL) FROM \\"" + 下层表.Replace("\\"", "\\"\\"") + "\\"),0)"; }''') # 4) 翻译公式 删参数 rep(''' private static string 翻译公式(string 表达式, Dictionary 层内公式, string 引用模式, string 下层表, out string 错误, bool 聚合用列引用 = false)''', ''' private static string 翻译公式(string 表达式, Dictionary 层内公式, string 引用模式, string 下层表, out string 错误)''') rep(''' { 引用模式 = 引用模式, 下层表 = 下层表, 层内公式 = 层内公式, 展开栈 = new HashSet(), 聚合用列引用 = 聚合用列引用 };''', ''' { 引用模式 = 引用模式, 下层表 = 下层表, 层内公式 = 层内公式, 展开栈 = new HashSet() };''') # 5) 生成Set片段 删参数 rep("private static string 生成Set片段(List<公式条目> 公式, string 引用模式, string 下层表, bool 聚合用列引用 = false)", "private static string 生成Set片段(List<公式条目> 公式, string 引用模式, string 下层表)") rep("string sql = 翻译公式(f.表达式, map, 引用模式, 下层表, out err, 聚合用列引用);", "string sql = 翻译公式(f.表达式, map, 引用模式, 下层表, out err);") rep("{ string e2; sql = 翻译公式(d[2], map, 引用模式, 下层表, out e2, 聚合用列引用); break; }", "{ string e2; sql = 翻译公式(d[2], map, 引用模式, 下层表, out e2); break; }") # 6) 建箱号表触发器:按行生成 rep(''' /// 为一张箱号表生成触发器(u/i/d):行内公式 + 所属图号行聚合。 public static void 建箱号表触发器(System.Data.SQLite.SQLiteConnection conn, System.Data.SQLite.SQLiteTransaction tx, string 箱号表, string 图号ID, string 图号表名, List<公式条目> 箱号公式, List<公式条目> 图号公式) { Drop触发器(conn, tx, 箱号表); string of = ""; foreach (var c in 箱号输入列) of += "\\"" + c + "\\","; of = of.TrimEnd(','); string xhSetNew = 生成Set片段(箱号公式, "NEW", null, true); // 本行(数量变);单台成本等由元件触发器维护 string xhSetRow = 生成Set片段(箱号公式, "ROW", 箱号表, true); // 同上 string thSet = 生成Set片段(图号公式, "ROW", 箱号表); string 刷图号 = "UPDATE \\"" + 图号表名 + "\\" SET " + thSet + " WHERE \\"内部ID\\"='" + 图号ID.Replace("'", "''") + "';"; Exec(conn, tx, "CREATE TRIGGER " + 触发器前缀 + Safe(箱号表) + "_u AFTER UPDATE OF " + of + " ON \\"" + 箱号表 + "\\" FOR EACH ROW BEGIN UPDATE \\"" + 箱号表 + "\\" SET " + xhSetNew + " WHERE rowid=NEW.rowid; " + 刷图号 + "END;"); Exec(conn, tx, "CREATE TRIGGER " + 触发器前缀 + Safe(箱号表) + "_i AFTER INSERT ON \\"" + 箱号表 + "\\" FOR EACH ROW BEGIN UPDATE \\"" + 箱号表 + "\\" SET " + xhSetRow + " WHERE rowid=NEW.rowid; " + 刷图号 + "END;"); Exec(conn, tx, "CREATE TRIGGER " + 触发器前缀 + Safe(箱号表) + "_d AFTER DELETE ON \\"" + 箱号表 + "\\" FOR EACH ROW BEGIN " + 刷图号 + "END;"); }''', ''' /// /// 为一张箱号表生成触发器。箱号聚合依赖"每行各自的元件表",数量更新触发器按行生成 /// (WHEN NEW."内部ID"=行ID,体内 SUM 子查询 FROM 该行的元件表);INSERT/DELETE 表级只刷图号聚合。 /// 行列表:每项 [箱号ID, 该行元件表名]。 /// public static void 建箱号表触发器(System.Data.SQLite.SQLiteConnection conn, System.Data.SQLite.SQLiteTransaction tx, string 箱号表, string 图号ID, string 图号表名, List 行列表, List<公式条目> 箱号公式, List<公式条目> 图号公式) { Drop触发器(conn, tx, 箱号表); string of = ""; foreach (var c in 箱号输入列) of += "\\"" + c + "\\","; of = of.TrimEnd(','); string thSet = 生成Set片段(图号公式, "ROW", 箱号表); string 刷图号 = "UPDATE \\"" + 图号表名 + "\\" SET " + thSet + " WHERE \\"内部ID\\"='" + 图号ID.Replace("'", "''") + "';"; foreach (var 行 in 行列表) { string 行ID = 行[0], yj表 = 行[1]; if (string.IsNullOrEmpty(yj表)) continue; string xhSetNew = 生成Set片段(箱号公式, "NEW", yj表); Exec(conn, tx, "CREATE TRIGGER " + 触发器前缀 + Safe(箱号表) + "_r_" + Safe(行ID) + "_u AFTER UPDATE OF " + of + " ON \\"" + 箱号表 + "\\" FOR EACH ROW WHEN NEW.\\"内部ID\\"='" + 行ID.Replace("'", "''") + "' BEGIN UPDATE \\"" + 箱号表 + "\\" SET " + xhSetNew + " WHERE rowid=NEW.rowid; " + 刷图号 + "END;"); } Exec(conn, tx, "CREATE TRIGGER " + 触发器前缀 + Safe(箱号表) + "_i AFTER INSERT ON \\"" + 箱号表 + "\\" FOR EACH ROW BEGIN " + 刷图号 + "END;"); Exec(conn, tx, "CREATE TRIGGER " + 触发器前缀 + Safe(箱号表) + "_d AFTER DELETE ON \\"" + 箱号表 + "\\" FOR EACH ROW BEGIN " + 刷图号 + "END;"); }''') # 7) 建图号行触发器:真 SUM rep(''' public static void 建图号行触发器(System.Data.SQLite.SQLiteConnection conn, System.Data.SQLite.SQLiteTransaction tx, string 图号表名, string 图号ID, List<公式条目> 图号公式) { string thSetNew = 生成Set片段(图号公式, "NEW", null, true);''', ''' public static void 建图号行触发器(System.Data.SQLite.SQLiteConnection conn, System.Data.SQLite.SQLiteTransaction tx, string 图号表名, string 图号ID, string 箱号表, List<公式条目> 图号公式) { string thSetNew = 生成Set片段(图号公式, "NEW", 箱号表);''') # 8) 重建项目全部触发器:组装行列表 rep(''' // 先建箱号表映射后建元件触发器(元件触发器引用箱号表名,顺序无碍;图号行触发器每图号一次) var 已建图号 = new HashSet(); foreach (var m in 箱号行列表) 建箱号表触发器(conn, tx, m[0], m[1], 图号表名, 箱号公式, 图号公式); foreach (var m in 元件表列表) 建元件表触发器(conn, tx, m[0], m[1], m[2], m[3], 图号表名, 元件公式, 箱号公式, 图号公式); foreach (var kv in 箱号表Of图号) if (已建图号.Add(kv.Key)) 建图号行触发器(conn, tx, 图号表名, kv.Key, 图号公式);''', ''' // 按箱号表分组元件表:[箱号表] → [箱号ID, 元件表] 列表 var 行按表 = new Dictionary>(); foreach (var m in 元件表列表) { List rows; if (!行按表.TryGetValue(m[1], out rows)) { rows = new List(); 行按表[m[1]] = rows; } rows.Add(new[] { m[2], m[0] }); } var 已建图号 = new HashSet(); foreach (var m in 箱号行列表) { List rows; if (!行按表.TryGetValue(m[0], out rows)) rows = new List(); 建箱号表触发器(conn, tx, m[0], m[1], 图号表名, rows, 箱号公式, 图号公式); } foreach (var m in 元件表列表) 建元件表触发器(conn, tx, m[0], m[1], m[2], m[3], 图号表名, 元件公式, 箱号公式, 图号公式); foreach (var kv in 箱号表Of图号) if (已建图号.Add(kv.Key)) 建图号行触发器(conn, tx, 图号表名, kv.Key, kv.Value, 图号公式);''') # 9) 建新表触发器:箱号分支传空行列表 rep(''' else if (新表类型 == "箱号") 建箱号表触发器(conn, tx, 箱号表, 图号ID, 图号表名, 箱号公式, 图号公式);''', ''' else if (新表类型 == "箱号") { // 新箱号表暂无行级元件表映射;行级触发器由"建元件表触发器时同批重建/进项目自检"补齐 建箱号表触发器(conn, tx, 箱号表, 图号ID, 图号表名, new List(), 箱号公式, 图号公式); }''') io.open(P, "w", encoding="utf-8-sig").write(s) print("重构完成", n, "处")