diff --git a/src/SheetMe.Core/Serialization/LegacyTypeCatalog.cs b/src/SheetMe.Core/Serialization/LegacyTypeCatalog.cs
index 0dba75e..56082a3 100644
--- a/src/SheetMe.Core/Serialization/LegacyTypeCatalog.cs
+++ b/src/SheetMe.Core/Serialization/LegacyTypeCatalog.cs
@@ -14,6 +14,17 @@ public static class LegacyTypeCatalog
/// 페이지 루트 클래스 단축명
public const string HostClassName = "MDesignerHost";
+ ///
+ /// 데이터소스의 중립 타입명 — 레거시 클래스명은 MDataTable 이고 여기서 이 이름으로 바뀐다.
+ ///
+ /// 상수로 두는 이유. 두 이름이 공존해서 실제로 사고가 났다.
+ /// 배선 실행기가 레거시 이름(MDataTable)으로 컨트롤을 찾고 있었는데,
+ /// 서식을 XML 에서 읽으면 그 시점에 이미 중립 이름으로 바뀌어 있어 한 개도 못 찾았다 —
+ /// 실사용 서식의 데이터소스 배선이 전부 "이 서식에 없습니다"로 죽었다.
+ /// 문자열을 각자 적는 한 같은 일이 또 난다.
+ ///
+ public const string DataTableType = "DataTable";
+
/// 페이지 루트 AQN (실샘플 sheetdesign.xml 원문 확인)
public const string HostAqn =
"M.EMR.UserControl.MDesignerHost, M.EMR.UserControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
@@ -42,7 +53,7 @@ public static class LegacyTypeCatalog
["MPictureBox"] = "PictureBox",
["MCalcBox"] = "CalcBox",
["MButton"] = "Button",
- ["MDataTable"] = "DataTable",
+ ["MDataTable"] = DataTableType,
// Spread 는 읽기 매핑만(렌더) — E_SpdMst 디자인 없이는 신규 생성 불가하므로 쓰기 매핑/팔레트 미등록
["Spread"] = "Spread",
};
diff --git a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs
index 9ffe707..0332303 100644
--- a/src/SheetMe.Designer/Diagnostics/DbSmoke.cs
+++ b/src/SheetMe.Designer/Diagnostics/DbSmoke.cs
@@ -2266,7 +2266,7 @@ public static class DbSmoke
probeDoc.Pages.Add(probePage);
var probeSource = new SheetMe.Core.Models.ControlElement
{
- Type = "MDataTable", Id = "MDataTable1",
+ Type = SheetMe.Core.Serialization.LegacyTypeCatalog.DataTableType, Id = "MDataTable1",
Bounds = new SheetMe.Core.Models.LayoutRect { X = 0, Y = 0, W = 20, H = 20 },
};
// 스칼라 치환과 DataRow 치환을 한 문장에 넣는다 — 둘은 다른 코드 경로다
diff --git a/src/SheetMe.Designer/Diagnostics/DialogShots.cs b/src/SheetMe.Designer/Diagnostics/DialogShots.cs
index d3a0f68..68b0052 100644
--- a/src/SheetMe.Designer/Diagnostics/DialogShots.cs
+++ b/src/SheetMe.Designer/Diagnostics/DialogShots.cs
@@ -462,7 +462,7 @@ public static class DialogShots
{
var source = new SheetMe.Core.Models.ControlElement
{
- Type = "MDataTable", Id = id,
+ Type = SheetMe.Core.Serialization.LegacyTypeCatalog.DataTableType, Id = id,
Bounds = new SheetMe.Core.Models.LayoutRect { X = 0, Y = 0, W = 20, H = 20 },
};
source.Props.SetText("Query", query);
diff --git a/src/SheetMe.Designer/Diagnostics/EditSmoke.cs b/src/SheetMe.Designer/Diagnostics/EditSmoke.cs
index 2800a6f..4eae119 100644
--- a/src/SheetMe.Designer/Diagnostics/EditSmoke.cs
+++ b/src/SheetMe.Designer/Diagnostics/EditSmoke.cs
@@ -392,7 +392,7 @@ public static class EditSmoke
}
host.Children.Add(new ControlElement
{
- Type = "MDataTable", Id = "안쪽데이터소스",
+ Type = SheetMe.Core.Serialization.LegacyTypeCatalog.DataTableType, Id = "안쪽데이터소스",
Bounds = new LayoutRect { X = 10, Y = 90, W = 120, H = 40 },
});
boxedPage.Controls.Add(host);
@@ -736,7 +736,7 @@ public static class EditSmoke
fieldDoc.Pages.Add(fieldPage);
var source = new ControlElement
{
- Type = "MDataTable", Id = "MDataTable1",
+ Type = SheetMe.Core.Serialization.LegacyTypeCatalog.DataTableType, Id = "MDataTable1",
Bounds = new LayoutRect { X = 0, Y = 0, W = 20, H = 20 },
};
source.Props.SetText("Query", "SELECT 'ㄱ' NAM FROM DUAL");
@@ -1112,6 +1112,37 @@ public static class EditSmoke
$"ValueText='{choiceRow.ValueText}' IsMixed={choiceRow.IsMixed}");
}
+ // 15-a000) 데이터소스를 실사용과 같은 경로로 만들었을 때도 러너가 찾는가.
+ //
+ // 이 검사가 없어서 배선 전체가 실사용에서 죽어 있는 것을 오래 못 봤다.
+ // 러너는 레거시 클래스명("MDataTable")으로 컨트롤을 찾고 있었는데, 서식을 XML 에서 읽으면
+ // 그 순간 중립 이름("DataTable")으로 바뀌어 있어 한 개도 못 모았다 —
+ // 모든 DataTableField 가 "이 서식에 없습니다"로 실패해 종이에서 빈칸이 됐다.
+ // 그런데 진단들이 ControlElement 를 손으로 만들며 같은 레거시 이름을 써서
+ // 러너의 오타와 짝이 맞아 전부 초록이었다. 그래서 여기서는 손으로 만들지 않는다.
+ {
+ Check("타입명: 레거시 MDataTable 은 중립 DataTable 로 읽힌다",
+ SheetMe.Core.Serialization.LegacyTypeCatalog.DataTableType == "DataTable");
+
+ var dsDoc = new DesignerViewModel(new FormDesignDataBusiness().CreateNew());
+ dsDoc.AddControlAt("DataTable", new Point(60, 60)); // 팔레트가 쓰는 그 경로
+ var made = dsDoc.Pages[0].Controls.Single(c => c.Type == "DataTable");
+ made.Model.Props.SetText("Query", "SELECT 1 FROM DUAL");
+
+ var runner = new Services.MDataTableRunner(dsDoc.Document, null);
+ Check("배선: 팔레트로 만든 데이터소스를 러너가 찾는다",
+ runner.Names.Count == 1 && runner.Names[0] == made.Id,
+ runner.Names.Count == 0 ? "0개 — 러너가 타입명을 잘못 보고 있다"
+ : string.Join(",", runner.Names));
+
+ // 이름으로 가리키는 배선이 실제로 그 데이터소스에 닿는가(값은 DB 없이 못 내지만
+ // '이 서식에 없습니다'로 떨어지면 안 된다)
+ var spec = SheetMe.Core.Catalog.DataTableFieldSpec.Parse($"{made.Id}.Rows(0).Item(\"NAM\")");
+ var reason = spec is null ? "(형식 파싱 실패)" : runner.Resolve(spec).Text;
+ Check("배선: '이 서식에 없습니다'로 떨어지지 않는다",
+ !reason.Contains("이 서식에 없습니다", StringComparison.Ordinal), reason);
+ }
+
// 15-a00) 아이콘 기본색이 검정으로 떨어지지 않는다.
//
// 색도 리소스 키도 안 준 아이콘이 Brushes.Black 으로 칠해지고 있었다.
diff --git a/src/SheetMe.Designer/Services/MDataTableRunner.cs b/src/SheetMe.Designer/Services/MDataTableRunner.cs
index aada052..cb4be44 100644
--- a/src/SheetMe.Designer/Services/MDataTableRunner.cs
+++ b/src/SheetMe.Designer/Services/MDataTableRunner.cs
@@ -1,5 +1,6 @@
using SheetMe.Core.Catalog;
using SheetMe.Core.Models;
+using SheetMe.Core.Serialization;
using SheetMe.Data.Stores;
namespace SheetMe.Designer.Services;
@@ -141,7 +142,13 @@ public sealed class MDataTableRunner : IDataFieldResolver
{
foreach (var control in controls)
{
- if (control.Type == "MDataTable")
+ // 중립 타입명으로 비교한다. 여기가 레거시 클래스명("MDataTable")을 보고 있어서
+ // 실사용 서식에서는 데이터소스를 한 개도 못 모았다 — XML 에서 읽는 순간
+ // LegacyTypeCatalog 가 이미 "DataTable" 로 바꿔 두기 때문이다.
+ // 그 결과 모든 DataTableField 배선이 "데이터소스 X 이 이 서식에 없습니다"로 실패해
+ // 미리보기·인쇄에서 빈칸이 됐고, 미리보기의 '데이터소스...' 버튼은 영영 회색이었다.
+ // 진단들이 ControlElement 를 손으로 만들며 같은 레거시 이름을 써서 초록으로 통과하고 있었다.
+ if (string.Equals(control.Type, LegacyTypeCatalog.DataTableType, StringComparison.Ordinal))
{
queries[control.Id] = control.Props.GetText("Query") ?? string.Empty;
}