제자리 갱신 시 E_SctMst.SctObjTxt 갱신 누락 수정
ShtCneYon='Y' 서식은 기존 이름 행을 continue 로 건너뛰기만 해서, 라벨 문구를 고쳐도 항목사전(SctObjTxt)이 옛 문구로 남았다. 이 값은 외부인터페이스·환자전달사항· 알람이 리터럴로 매칭하는 조회 키라 조용한 데이터 불일치가 된다. 레거시 bzSaveSheetDesignNControlInfo.vb:378 과 동일하게 SctObjTxt 만 덮어쓴다: - SctObjTyp/SctParObj/SctObjSeq/SctObjID 는 갱신하지 않음(SctKey 보존 의미론) - 삭제된 컨트롤의 잔존 행도 지우지 않음(레거시 동일) - SctKey 기준 UPDATE — 동명 중복 오염 데이터에서 다중 행 덮어쓰기 방지 - Spread AsTemplate 항목 행은 ObjName 이 항목 텍스트라 컨트롤 이름과 분리해 매칭. 레거시의 매 저장 중복 INSERT 버그는 복제하지 않는다(런타임이 개수를 세지 않음). --db-save-smoke 에 문구 변경 검증 추가 — 무변경 재저장으로는 이 경로를 증명할 수 없으므로 실제로 Text 를 바꿔 SctObjTxt 반영·SctKey 보존을 확인하고 원복한다. 검증: P163(ShtCneYon=Y) 2회 연속 통과(행 6/6 안정, SctKey 보존, 원복 확인), S999(버저닝) diff 0 + 이전 버전 SdgDelYon='Y', 전수 왕복 1,271건 diff 0/예외 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
16c07f48dc
commit
20e982faae
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using SheetMe.Core.Models;
|
||||
using SheetMe.Core.Serialization;
|
||||
using SheetMe.Data.Stores;
|
||||
using SheetMe.Designer.Services;
|
||||
@@ -337,6 +338,107 @@ public static class DbSmoke
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 제자리 갱신(ShtCneYon='Y') 서식에서 컨트롤 문구를 실제로 바꿔 E_SctMst.SctObjTxt 반영을 확인하고 원복한다.
|
||||
/// 레거시 bzSaveSheetDesignNControlInfo.vb:378 은 기존 행의 SctObjTxt 만 덮어쓰고 SctKey 는 보존하므로
|
||||
/// 둘 다 검사한다. 확인 후 원문으로 되돌려 DB 상태를 원위치시킨다.
|
||||
/// </summary>
|
||||
private static bool VerifySctObjTxtUpdate(OracleLegacyFormStore store, LegacyXmlSerializer serializer,
|
||||
string connectionString, string shtCod, decimal sdgKey, List<string> lines)
|
||||
{
|
||||
var raw = store.LoadActiveDesignRaw(shtCod);
|
||||
if (raw is null)
|
||||
{
|
||||
lines.Add("[SctObjTxt] 활성 디자인 조회 실패");
|
||||
return false;
|
||||
}
|
||||
|
||||
var document = serializer.Read(raw.Value.Xml);
|
||||
document.FormId = shtCod;
|
||||
var target = EnumerateControls(document).FirstOrDefault(c => (c.Props.GetText("Text") ?? string.Empty).Length > 0);
|
||||
if (target is null)
|
||||
{
|
||||
lines.Add("[SctObjTxt] Text 를 가진 컨트롤이 없어 검사 생략(통과로 간주)");
|
||||
return true;
|
||||
}
|
||||
|
||||
var originalText = target.Props.GetText("Text")!;
|
||||
var probeText = originalText + "_SCTPROBE";
|
||||
var (keyBefore, txtBefore) = ReadSctRow(connectionString, sdgKey, target.Id);
|
||||
lines.Add($"[SctObjTxt] 대상 '{target.Id}' SctKey={keyBefore} 원문='{Trim30(txtBefore)}'");
|
||||
|
||||
try
|
||||
{
|
||||
target.Props.SetText("Text", probeText);
|
||||
store.SaveDesign(document, Environment.UserName);
|
||||
var (keyAfter, txtAfter) = ReadSctRow(connectionString, sdgKey, target.Id);
|
||||
var textApplied = string.Equals(txtAfter, probeText, StringComparison.Ordinal);
|
||||
var keyStable = keyAfter == keyBefore;
|
||||
lines.Add($"[SctObjTxt] 변경 후 SctKey={keyAfter}({(keyStable ? "보존" : "변동!")}) " +
|
||||
$"SctObjTxt='{Trim30(txtAfter)}' → {(textApplied ? "반영됨" : "미반영!")}");
|
||||
return textApplied && keyStable;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 원복 — 검사 실패 여부와 무관하게 DB 를 원상태로 되돌린다
|
||||
var restore = serializer.Read(store.LoadActiveDesignRaw(shtCod)!.Value.Xml);
|
||||
restore.FormId = shtCod;
|
||||
var restoreTarget = EnumerateControls(restore).FirstOrDefault(c => c.Id == target.Id);
|
||||
if (restoreTarget is not null)
|
||||
{
|
||||
restoreTarget.Props.SetText("Text", originalText);
|
||||
store.SaveDesign(restore, Environment.UserName);
|
||||
var (_, txtRestored) = ReadSctRow(connectionString, sdgKey, target.Id);
|
||||
lines.Add($"[SctObjTxt] 원복 → '{Trim30(txtRestored)}' " +
|
||||
$"{(string.Equals(txtRestored, originalText, StringComparison.Ordinal) ? "확인" : "불일치!")}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>E_SctMst 단일 행의 (SctKey, SctObjTxt) — 동명 중복 시 최초 1건</summary>
|
||||
private static (decimal Key, string Text) ReadSctRow(string connectionString, decimal sdgKey, string objName)
|
||||
{
|
||||
using var connection = new Oracle.ManagedDataAccess.Client.OracleConnection(connectionString);
|
||||
connection.Open();
|
||||
using var command = connection.CreateCommand();
|
||||
command.BindByName = true;
|
||||
command.CommandText =
|
||||
"SELECT SctKey, NVL(SctObjTxt,' ') FROM E_SctMst WHERE SctSdgKey = :k AND SctObjNam = :n ORDER BY SctKey";
|
||||
command.Parameters.Add(new Oracle.ManagedDataAccess.Client.OracleParameter("k", sdgKey));
|
||||
command.Parameters.Add(new Oracle.ManagedDataAccess.Client.OracleParameter("n", objName));
|
||||
using var reader = command.ExecuteReader();
|
||||
return reader.Read() ? (reader.GetDecimal(0), reader.GetString(1)) : (0m, string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>문서의 모든 컨트롤(자식 포함) 평탄화</summary>
|
||||
private static IEnumerable<ControlElement> EnumerateControls(FormDocument document)
|
||||
{
|
||||
foreach (var page in document.Pages)
|
||||
{
|
||||
foreach (var control in page.Controls)
|
||||
{
|
||||
foreach (var item in Flatten(control))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static IEnumerable<ControlElement> Flatten(ControlElement element)
|
||||
{
|
||||
yield return element;
|
||||
foreach (var child in element.Children)
|
||||
{
|
||||
foreach (var item in Flatten(child))
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string Trim30(string value) => value.Length > 30 ? value[..30] + "…" : value;
|
||||
|
||||
/// <summary>무변경 재저장 스모크 — 저장 경로 전체(트랜잭션/버저닝/E_SctMst) 검증</summary>
|
||||
public static int RunSaveSmoke(string shtCod, string reportPath)
|
||||
{
|
||||
@@ -378,6 +480,14 @@ public static class DbSmoke
|
||||
}
|
||||
|
||||
var ok = diffs.Count == 0 && sctCount == walkerCount;
|
||||
|
||||
// 제자리 갱신 경로에서만 의미가 있는 검사 — 무변경 재저장으로는 SctObjTxt 갱신을 증명할 수 없으므로
|
||||
// 문구를 실제로 바꿔 E_SctMst 에 반영되는지 확인하고 원복한다(레거시는 SctObjTxt 만 덮어쓴다).
|
||||
if (ok && cneYon == "Y")
|
||||
{
|
||||
ok &= VerifySctObjTxtUpdate(store, serializer, config.ConnectionString, shtCod, savedKey, lines);
|
||||
}
|
||||
|
||||
lines.Add(ok ? "결과: 통과 — 레거시 디자이너/EMR 미리보기로 열어 최종 육안 확인 권장" : "결과: 실패");
|
||||
File.WriteAllText(reportPath, string.Join(Environment.NewLine, lines));
|
||||
return ok ? 0 : 1;
|
||||
|
||||
Reference in New Issue
Block a user