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;
|
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(
|
var compositions = await session.GetCompositionsAsync(
|
||||||
template.Id,
|
template.Id,
|
||||||
id => _templateRepo.GetCompositionsByTemplateIdAsync(id, cancellationToken));
|
_ => Task.FromResult<IReadOnlyList<Commons.Entities.Templates.TemplateComposition>>(
|
||||||
|
loaded.Compositions.ToList()));
|
||||||
if (compositions.Count == 0) continue;
|
if (compositions.Count == 0) continue;
|
||||||
|
|
||||||
compositionMap[template.Id] = compositions;
|
compositionMap[template.Id] = compositions;
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ public class DeploymentComparisonTests
|
|||||||
|
|
||||||
templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
||||||
templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||||
templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>()).Returns([]);
|
|
||||||
templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
||||||
siteRepo.GetDataConnectionsBySiteIdAsync(SiteId, 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(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||||
_templateRepo.GetTemplateWithChildrenAsync(ParentTemplateId, Arg.Any<CancellationToken>()).Returns(parent);
|
_templateRepo.GetTemplateWithChildrenAsync(ParentTemplateId, Arg.Any<CancellationToken>()).Returns(parent);
|
||||||
_templateRepo.GetCompositionsByTemplateIdAsync(Arg.Any<int>(), Arg.Any<CancellationToken>()).Returns([]);
|
|
||||||
|
|
||||||
for (var i = 1; i <= instanceCount; i++)
|
for (var i = 1; i <= instanceCount; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
-1
@@ -72,7 +72,6 @@ public class FlatteningPipelineConnectionBindingTests
|
|||||||
|
|
||||||
_templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
_templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
||||||
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||||
_templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>()).Returns([]);
|
|
||||||
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
||||||
|
|
||||||
var connection = new DataConnection("PlantBus", "OpcUa", SiteId) { Id = ConnectionId };
|
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.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>()).Returns(instance);
|
||||||
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(template);
|
||||||
_templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>())
|
|
||||||
.Returns([]);
|
|
||||||
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>())
|
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>())
|
||||||
.Returns([]);
|
.Returns([]);
|
||||||
|
|
||||||
|
|||||||
+19
-2
@@ -52,8 +52,8 @@ public class FlatteningPipelinePreviewTests
|
|||||||
|
|
||||||
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(parent);
|
_templateRepo.GetTemplateWithChildrenAsync(TemplateId, Arg.Any<CancellationToken>()).Returns(parent);
|
||||||
_templateRepo.GetTemplateWithChildrenAsync(ModuleTemplateId, Arg.Any<CancellationToken>()).Returns(module);
|
_templateRepo.GetTemplateWithChildrenAsync(ModuleTemplateId, Arg.Any<CancellationToken>()).Returns(module);
|
||||||
_templateRepo.GetCompositionsByTemplateIdAsync(TemplateId, Arg.Any<CancellationToken>()).Returns([composition]);
|
// Compositions ride on the loaded template (GetTemplateWithChildrenAsync Includes them).
|
||||||
_templateRepo.GetCompositionsByTemplateIdAsync(ModuleTemplateId, Arg.Any<CancellationToken>()).Returns([]);
|
parent.Compositions.Add(composition);
|
||||||
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
_templateRepo.GetAllSharedScriptsAsync(Arg.Any<CancellationToken>()).Returns([]);
|
||||||
_templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>())
|
_templateRepo.GetInstanceByIdAsync(InstanceId, Arg.Any<CancellationToken>())
|
||||||
.Returns(new Instance("Line-01") { Id = InstanceId, TemplateId = TemplateId, SiteId = SiteId });
|
.Returns(new Instance("Line-01") { Id = InstanceId, TemplateId = TemplateId, SiteId = SiteId });
|
||||||
@@ -101,4 +101,21 @@ public class FlatteningPipelinePreviewTests
|
|||||||
await _sut.PreviewAsync(TemplateId, SiteId);
|
await _sut.PreviewAsync(TemplateId, SiteId);
|
||||||
await _templateRepo.DidNotReceive().GetInstanceByIdAsync(Arg.Any<int>(), Arg.Any<CancellationToken>());
|
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