fix(deployment): flatten reads compositions off the loaded template instead of a second per-template query (review 2026-10-21 04/U5)
This commit is contained in:
@@ -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<IReadOnlyList<Commons.Entities.Templates.TemplateComposition>>(
|
||||
loaded.Compositions.ToList()));
|
||||
if (compositions.Count == 0) continue;
|
||||
|
||||
compositionMap[template.Id] = compositions;
|
||||
|
||||
@@ -96,7 +96,6 @@ public class DeploymentComparisonTests
|
||||
|
||||
templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
||||
templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||
templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>()).Returns([]);
|
||||
templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
||||
siteRepo.GetDataConnectionsBySiteIdAsync(SiteId, Arg.Any<CancellationToken>()).Returns([]);
|
||||
|
||||
|
||||
@@ -59,7 +59,6 @@ public class FlattenSessionCacheTests
|
||||
|
||||
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||
_templateRepo.GetTemplateWithChildrenAsync(ParentTemplateId, Arg.Any<CancellationToken>()).Returns(parent);
|
||||
_templateRepo.GetCompositionsByTemplateIdAsync(Arg.Any<int>(), Arg.Any<CancellationToken>()).Returns([]);
|
||||
|
||||
for (var i = 1; i <= instanceCount; i++)
|
||||
{
|
||||
|
||||
-1
@@ -72,7 +72,6 @@ public class FlatteningPipelineConnectionBindingTests
|
||||
|
||||
_templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
||||
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||
_templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>()).Returns([]);
|
||||
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
||||
|
||||
var connection = new DataConnection("PlantBus", "OpcUa", SiteId) { Id = ConnectionId };
|
||||
|
||||
-2
@@ -64,8 +64,6 @@ public class FlatteningPipelineNativeAlarmCapabilityTests
|
||||
|
||||
_templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
||||
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||
_templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>())
|
||||
.Returns([]);
|
||||
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>())
|
||||
.Returns([]);
|
||||
|
||||
|
||||
+19
-2
@@ -52,8 +52,8 @@ public class FlatteningPipelinePreviewTests
|
||||
|
||||
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(parent);
|
||||
_templateRepo.GetTemplateWithChildrenAsync(ModuleTemplateId, Arg.Any<CancellationToken>()).Returns(module);
|
||||
_templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>()).Returns([composition]);
|
||||
_templateRepo.GetCompositionsByTemplateIdAsync(ModuleTemplateId, Arg.Any<CancellationToken>()).Returns([]);
|
||||
// Compositions ride on the loaded template (GetTemplateWithChildrenAsync Includes them).
|
||||
parent.Compositions.Add(composition);
|
||||
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
||||
_templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>())
|
||||
.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<int>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[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<int>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user