From 3782ebdadb8513f3642fcb43acbc9b6dbef363f6 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 18 Jun 2026 07:56:00 -0400 Subject: [PATCH] fix(transport): skip unbound (empty ConnectionName) bindings on import instead of writing FK=0 (M8 INT review) --- .../Import/BundleImporter.cs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/ZB.MOM.WW.ScadaBridge.Transport/Import/BundleImporter.cs b/src/ZB.MOM.WW.ScadaBridge.Transport/Import/BundleImporter.cs index c91d64e5..6c8a4d31 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Transport/Import/BundleImporter.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Transport/Import/BundleImporter.cs @@ -3237,25 +3237,28 @@ public sealed class BundleImporter : IBundleImporter } foreach (var b in dto.ConnectionBindings) { + // A binding may carry NO connection name — an unbound attribute, or a + // binding whose source connection was not included in the export. There + // is no meaningful target FK to write (DataConnectionId = 0 would be an + // invalid FK and FK-violate at commit on a relational provider), so skip + // the binding row entirely rather than persist a broken binding. + if (string.IsNullOrEmpty(b.ConnectionName)) + { + continue; + } // Resolve ConnectionName → target DataConnectionId. After the C1 Pass-2 // in ApplyDataConnectionsAsync, the map carries an entry for every // referenced connection — carried in the bundle OR auto-matched in the - // target. A binding whose connection name STILL doesn't resolve is a - // structural error (it should already have been a preview blocker + - // a pre-write validation failure); THROW rather than write - // DataConnectionId = 0, which would be an invalid FK on a relational - // provider and a silently-broken binding on the in-memory one. - // A binding may legitimately carry NO connection name (unbound - // attribute) — only a NON-EMPTY name that fails to resolve is an error. - if (!string.IsNullOrEmpty(b.ConnectionName) - && !connectionMaps.IdBySourceRef.TryGetValue((sourceSiteIdentifier, b.ConnectionName), out _)) + // target. A non-empty name that STILL doesn't resolve is a structural + // error (it should already have been a preview blocker + a pre-write + // validation failure); THROW rather than write an invalid FK. + if (!connectionMaps.IdBySourceRef.TryGetValue((sourceSiteIdentifier, b.ConnectionName), out var connId)) { throw new InvalidOperationException( $"Instance '{inst.UniqueName}' binding for attribute '{b.AttributeName}' references " + $"connection '{sourceSiteIdentifier}/{b.ConnectionName}' which could not be resolved " + "to a target connection (present in neither bundle nor target)."); } - connectionMaps.IdBySourceRef.TryGetValue((sourceSiteIdentifier, b.ConnectionName), out var connId); inst.ConnectionBindings.Add(new InstanceConnectionBinding(b.AttributeName) { DataConnectionId = connId,