diff --git a/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs b/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs index 335348f2..7cdf476f 100644 --- a/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs +++ b/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/FlatteningPipeline.cs @@ -240,9 +240,14 @@ public class FlatteningPipeline : IFlatteningPipeline { if (!processedTemplateIds.Add(template.Id)) continue; + // The chain's templates come from GetTemplateWithChildrenAsync, which already + // Includes Compositions — read them off the loaded entity rather than issuing a + // second per-template composition query. + var loaded = template; var compositions = await session.GetCompositionsAsync( template.Id, - id => _templateRepo.GetCompositionsByTemplateIdAsync(id, cancellationToken)); + _ => Task.FromResult>( + loaded.Compositions.ToList())); if (compositions.Count == 0) continue; compositionMap[template.Id] = compositions; diff --git a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploymentComparisonTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploymentComparisonTests.cs index 941caaa6..5e1bc534 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploymentComparisonTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/DeploymentComparisonTests.cs @@ -96,7 +96,6 @@ public class DeploymentComparisonTests templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any()).Returns(instance); templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any()).Returns(template); - templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any()).Returns([]); templateRepo.GetAllSharedScriptsAsync(Arg.Any()).Returns([]); siteRepo.GetDataConnectionsBySiteIdAsync(SiteId, Arg.Any()).Returns([]); diff --git a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlattenSessionCacheTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlattenSessionCacheTests.cs index f94af317..1fc2ffce 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlattenSessionCacheTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlattenSessionCacheTests.cs @@ -59,7 +59,6 @@ public class FlattenSessionCacheTests _templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any()).Returns(template); _templateRepo.GetTemplateWithChildrenAsync(ParentTemplateId, Arg.Any()).Returns(parent); - _templateRepo.GetCompositionsByTemplateIdAsync(Arg.Any(), Arg.Any()).Returns([]); for (var i = 1; i <= instanceCount; i++) { diff --git a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineConnectionBindingTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineConnectionBindingTests.cs index 3105bea3..35eaf9ba 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineConnectionBindingTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineConnectionBindingTests.cs @@ -72,7 +72,6 @@ public class FlatteningPipelineConnectionBindingTests _templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any()).Returns(instance); _templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any()).Returns(template); - _templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any()).Returns([]); _templateRepo.GetAllSharedScriptsAsync(Arg.Any()).Returns([]); var connection = new DataConnection("PlantBus", "OpcUa", SiteId) { Id = ConnectionId }; diff --git a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs index 46519228..2c7ba580 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelineNativeAlarmCapabilityTests.cs @@ -64,8 +64,6 @@ public class FlatteningPipelineNativeAlarmCapabilityTests _templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any()).Returns(instance); _templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any()).Returns(template); - _templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any()) - .Returns([]); _templateRepo.GetAllSharedScriptsAsync(Arg.Any()) .Returns([]); diff --git a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelinePreviewTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelinePreviewTests.cs index ba7fcfcd..731800af 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelinePreviewTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests/FlatteningPipelinePreviewTests.cs @@ -52,8 +52,8 @@ public class FlatteningPipelinePreviewTests _templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any()).Returns(parent); _templateRepo.GetTemplateWithChildrenAsync(ModuleTemplateId, Arg.Any()).Returns(module); - _templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any()).Returns([composition]); - _templateRepo.GetCompositionsByTemplateIdAsync(ModuleTemplateId, Arg.Any()).Returns([]); + // Compositions ride on the loaded template (GetTemplateWithChildrenAsync Includes them). + parent.Compositions.Add(composition); _templateRepo.GetAllSharedScriptsAsync(Arg.Any()).Returns([]); _templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any()) .Returns(new Instance("Line-01") { Id = InstanceId, TemplateId = TemplateId, SiteId = SiteId }); @@ -101,4 +101,21 @@ public class FlatteningPipelinePreviewTests await _sut.PreviewAsync(TemplateId, SiteId); await _templateRepo.DidNotReceive().GetInstanceByIdAsync(Arg.Any(), Arg.Any()); } + + /// + /// review 2026-10-21 04/U5: the composition walk reads compositions off the already-loaded + /// template (GetTemplateWithChildrenAsync Includes them) and issues no separate + /// per-template composition query — while still resolving the composed module. + /// + /// A task that represents the asynchronous operation. + [Fact] + public async Task Flatten_reads_compositions_from_loaded_template_without_extra_query() + { + var result = await _sut.FlattenAndValidateAsync(InstanceId, validateScripts: false); + + Assert.True(result.IsSuccess, result.IsSuccess ? "" : result.Error); + Assert.Contains(result.Value.Configuration.Attributes, a => a.CanonicalName == "Left.MoveInFlag"); + await _templateRepo.DidNotReceive().GetCompositionsByTemplateIdAsync( + Arg.Any(), Arg.Any()); + } }