feat(configdb): V2HostingAlignment migration consolidating Phase 1a-1e
Phase 1f — the consolidator migration. Closes out the v2 entity-model
rewrite by emitting a single EF migration that captures the cumulative
schema delta from 14a (RowVersion) through 14e (drop generation entities).
Generated: src/Core/ZB.MOM.WW.OtOpcUa.Configuration/Migrations/
20260526081556_V2HostingAlignment.cs (1562 lines)
20260526081556_V2HostingAlignment.Designer.cs
Migration shape (per `grep -nE migrationBuilder.\(...)`):
Drop 12 ForeignKey constraints (one per live-edit entity's GenerationId FK)
Drop 2 Tables (ConfigGeneration, ClusterNodeGenerationState)
Drop 45 Indexes (every UX_*_Generation_* and IX_*_Generation_* across the
13 live-edit tables — 1 also dropped the unique-Primary
filtered index UX_ClusterNode_Primary_Per_Cluster)
Drop 13 Columns (12 GenerationId + 1 RedundancyRole)
Add 12 RowVersion columns (one per live-edit entity)
Create 4 Tables (Deployment, NodeDeploymentState, ConfigEdit,
DataProtectionKeys)
Create ~45 Indexes (recreated under the new naming pattern
UX_<Table>_LogicalId / UX_<Table>_<X> with the
GenerationId column stripped from composite keys)
Notable EF quirks accepted:
Unique-on-required-column indexes (UX_VirtualTag_LogicalId etc.) ship a
`filter: "[VirtualTagId] IS NOT NULL"` clause that EF auto-inserts for
SQL Server. Harmless — the column is C#-side `required` so NULL never
appears.
Verification:
dotnet build src/Core/ZB.MOM.WW.OtOpcUa.Configuration -> 0 errors
dotnet ef migrations script --idempotent (against placeholder DSN)
-> 3259-line
.sql produced
OK
tests/Core/ZB.MOM.WW.OtOpcUa.Configuration.Tests -> 0 errors
Live `dotnet ef database update` against a scratch SQL Server deferred to
Task 15 (Migrate-To-V2.ps1) — SSH to the docker host needs a key/password I
don't have, and the always-on SQL at 10.100.0.35,14330 uses Integrated
Security (Windows auth, unreachable from this macOS dev). The migration
itself is structurally correct by construction (EF tooling generated it
against the live DbContext model); the live-DB confidence step is the
PowerShell wrapper's job.
SchemaComplianceTests updates:
- All_expected_tables_exist: removed ConfigGeneration +
ClusterNodeGenerationState; added Deployment, NodeDeploymentState,
ConfigEdit, DataProtectionKeys.
- Filtered_unique_indexes_match_schema_spec: removed entries for
UX_ClusterNode_Primary_Per_Cluster (Task 14d) and
UX_ConfigGeneration_Draft_Per_Cluster (Task 14e). Two filtered uniques
remain (UX_ClusterNodeCredential_Value, UX_ExternalIdReservation_KindValue_Active).
- Check_constraints_match_schema_spec: added CK_ConfigEdit_FieldsJson_IsJson.
StoredProceduresTests update:
- Removed RedundancyRole + 'Primary' from the raw INSERT into ClusterNode
so the DB-backed test runs against the new schema.
This commit is contained in:
@@ -23,8 +23,8 @@ public sealed class SchemaComplianceTests
|
||||
{
|
||||
var expected = new[]
|
||||
{
|
||||
"ServerCluster", "ClusterNode", "ClusterNodeCredential", "ClusterNodeGenerationState",
|
||||
"ConfigGeneration", "ConfigAuditLog",
|
||||
"ServerCluster", "ClusterNode", "ClusterNodeCredential",
|
||||
"ConfigAuditLog",
|
||||
"Namespace", "UnsArea", "UnsLine",
|
||||
"DriverInstance", "Device", "Equipment", "Tag", "PollGroup", "VirtualTag",
|
||||
"NodeAcl", "ExternalIdReservation",
|
||||
@@ -34,6 +34,8 @@ public sealed class SchemaComplianceTests
|
||||
"EquipmentImportBatch",
|
||||
"EquipmentImportRow",
|
||||
"Script", "ScriptedAlarm", "ScriptedAlarmState",
|
||||
// v2 deploy-model tables (Phase 1 of Akka + fused-hosting alignment)
|
||||
"Deployment", "NodeDeploymentState", "ConfigEdit", "DataProtectionKeys",
|
||||
};
|
||||
|
||||
var actual = QueryStrings(@"
|
||||
@@ -52,9 +54,7 @@ SELECT name FROM sys.tables WHERE name <> '__EFMigrationsHistory' ORDER BY name;
|
||||
// Kept here as a spec-level source of truth; the test ensures EF generated them verbatim.
|
||||
var expected = new[]
|
||||
{
|
||||
("UX_ClusterNode_Primary_Per_Cluster", "([RedundancyRole]='Primary')"),
|
||||
("UX_ClusterNodeCredential_Value", "([Enabled]=(1))"),
|
||||
("UX_ConfigGeneration_Draft_Per_Cluster", "([Status]='Draft')"),
|
||||
("UX_ExternalIdReservation_KindValue_Active", "([ReleasedAt] IS NULL)"),
|
||||
};
|
||||
|
||||
@@ -85,6 +85,7 @@ WHERE i.is_unique = 1 AND i.has_filter = 1;",
|
||||
"CK_PollGroup_IntervalMs_Min",
|
||||
"CK_Tag_TagConfig_IsJson",
|
||||
"CK_ConfigAuditLog_DetailsJson_IsJson",
|
||||
"CK_ConfigEdit_FieldsJson_IsJson",
|
||||
};
|
||||
|
||||
var actual = QueryStrings("SELECT name FROM sys.check_constraints ORDER BY name;").ToHashSet();
|
||||
|
||||
@@ -260,8 +260,8 @@ public sealed class StoredProceduresTests
|
||||
Exec(conn,
|
||||
@"INSERT dbo.ServerCluster (ClusterId, Name, Enterprise, Site, RedundancyMode, NodeCount, Enabled, CreatedBy)
|
||||
VALUES (@c, @c, 'zb', @s, 'None', 1, 1, SUSER_SNAME());
|
||||
INSERT dbo.ClusterNode (NodeId, ClusterId, RedundancyRole, Host, OpcUaPort, DashboardPort, ApplicationUri, ServiceLevelBase, Enabled, CreatedBy)
|
||||
VALUES (@n, @c, 'Primary', 'localhost', 4840, 5001, CONCAT('urn:localhost:', @s), 200, 1, SUSER_SNAME());
|
||||
INSERT dbo.ClusterNode (NodeId, ClusterId, Host, OpcUaPort, DashboardPort, ApplicationUri, ServiceLevelBase, Enabled, CreatedBy)
|
||||
VALUES (@n, @c, 'localhost', 4840, 5001, CONCAT('urn:localhost:', @s), 200, 1, SUSER_SNAME());
|
||||
INSERT dbo.ClusterNodeCredential (NodeId, Kind, Value, Enabled, CreatedBy)
|
||||
VALUES (@n, 'SqlLogin', SUSER_SNAME(), 1, SUSER_SNAME());",
|
||||
("c", clusterId), ("n", nodeId), ("s", suffix));
|
||||
|
||||
Reference in New Issue
Block a user