<Fix>: Correct test-dependent result evaluation in ResultsWriter, increase revision to 3.9.3145.101
Cause: - ResultsWriter evaluated selected test-dependent items without the actual TestID. - This caused values such as Test passed(), timestamps, flow, pressure, temperature, conductivity and error data to be empty or incorrect. Solution: 1. Fixed test-aware result evaluation - Uses published regular meter test results. - Passes mtr.Name() as TestID to item.Print(wm, testId). 2. Restored correct test result mapping - Test-dependent values are now resolved from the correct TestRslt / MeterTestRslt. 3. Increased revision - Updated revision to 3.9.3145.101.
This commit is contained in:
parent
054075a341
commit
d3c8813012
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("3.9.3145.100")]
|
||||
[assembly: AssemblyFileVersion("3.9.3145.100")]
|
||||
[assembly: AssemblyVersion("3.9.3145.101")]
|
||||
[assembly: AssemblyFileVersion("3.9.3145.101")]
|
||||
|
||||
@ -242,6 +242,13 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
/// <summary>
|
||||
/// Writes all enabled water meters in a batch.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// XML payload targets are generated once per batch. Every enabled water
|
||||
/// meter contributes one logical repeat record to the same XML document.
|
||||
///
|
||||
/// Legacy Insert output keeps its existing behavior: every published
|
||||
/// regular meter test is written with its concrete test ID context.
|
||||
/// </remarks>
|
||||
public void WriteBatchResults(
|
||||
Batch batch)
|
||||
{
|
||||
@ -256,11 +263,25 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
WriterCfg storageCfg =
|
||||
GetDataStorageWriterConfiguration();
|
||||
|
||||
XmlPayloadRequestBuilder payloadBuilder =
|
||||
storageCfg.UsesXmlPayload()
|
||||
? new XmlPayloadRequestBuilder(
|
||||
storageCfg)
|
||||
: null;
|
||||
if (storageCfg.UsesXmlPayload())
|
||||
{
|
||||
WriteXmlBatchResults(
|
||||
batch,
|
||||
storageCfg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (storageCfg.WriteMode !=
|
||||
WriteMode.Insert)
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
string.Format(
|
||||
"ResultsWriter does not support UniDataStorageWriter target '{0}' / '{1}' / '{2}'.",
|
||||
storageCfg.DataStorageType,
|
||||
storageCfg.TechnologyType,
|
||||
storageCfg.WriteMode));
|
||||
}
|
||||
|
||||
foreach (WaterMeter wm
|
||||
in batch.WaterMeters)
|
||||
@ -271,104 +292,141 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
continue;
|
||||
}
|
||||
|
||||
DataWriteRequest targetRequest;
|
||||
|
||||
if (storageCfg.IsStoredProcedurePayloadTarget())
|
||||
{
|
||||
PayloadGenerationRequest generationRequest =
|
||||
BuildPayloadGenerationRequest(
|
||||
wm);
|
||||
|
||||
XmlPayloadBuildResult buildResult =
|
||||
payloadBuilder.Build(
|
||||
generationRequest,
|
||||
Convert.ToString(
|
||||
wm.SerialNr));
|
||||
|
||||
targetRequest =
|
||||
buildResult.Request;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
buildResult.ArchiveFilePath))
|
||||
{
|
||||
log.InfoFormat(
|
||||
"XML payload archived to '{0}'.",
|
||||
buildResult.ArchiveFilePath);
|
||||
}
|
||||
}
|
||||
else if (storageCfg.IsXmlFileTarget())
|
||||
{
|
||||
PayloadGenerationRequest generationRequest =
|
||||
BuildPayloadGenerationRequest(
|
||||
wm);
|
||||
|
||||
XmlPayloadBuildResult buildResult =
|
||||
payloadBuilder.BuildFile(
|
||||
generationRequest,
|
||||
Convert.ToString(
|
||||
wm.SerialNr));
|
||||
|
||||
targetRequest =
|
||||
buildResult.Request;
|
||||
|
||||
log.InfoFormat(
|
||||
"XML file payload generated for WM position {0}: {1}",
|
||||
wm.WMPosition,
|
||||
buildResult.OutputFileName);
|
||||
}
|
||||
else if (storageCfg.WriteMode ==
|
||||
WriteMode.Insert)
|
||||
{
|
||||
targetRequest =
|
||||
BuildInsertRequest(
|
||||
wm);
|
||||
|
||||
if (targetRequest.InsertItems.Count == 0)
|
||||
{
|
||||
log.WarnFormat(
|
||||
"No values to write for WM position {0}",
|
||||
wm.WMPosition);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
string.Format(
|
||||
"ResultsWriter does not support UniDataStorageWriter target '{0}' / '{1}' / '{2}'.",
|
||||
storageCfg.DataStorageType,
|
||||
storageCfg.TechnologyType,
|
||||
storageCfg.WriteMode));
|
||||
}
|
||||
|
||||
WriterDiagnosticResult result =
|
||||
dataStorageWriter.SetData(
|
||||
targetRequest);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
throw new Exception(
|
||||
result.Message);
|
||||
}
|
||||
|
||||
log.WarnFormat(
|
||||
"ResultsWriter wrote WM position {0}. Target={1}, Technology={2}, Mode={3}.",
|
||||
wm.WMPosition,
|
||||
storageCfg.DataStorageType,
|
||||
storageCfg.TechnologyType,
|
||||
storageCfg.WriteMode);
|
||||
//
|
||||
// Insert mode needs the same test context as the legacy TBF
|
||||
// result writers. One row is generated for every published
|
||||
// regular meter test and all selected items are evaluated
|
||||
// with the actual mtr.Name() as test ID.
|
||||
//
|
||||
WriteInsertResults(
|
||||
wm,
|
||||
storageCfg);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates and writes one XML payload for the complete batch.
|
||||
/// </summary>
|
||||
private void WriteXmlBatchResults(
|
||||
Batch batch,
|
||||
WriterCfg storageCfg)
|
||||
{
|
||||
IList<WaterMeter> enabledMeters =
|
||||
batch.WaterMeters
|
||||
.Where(
|
||||
wm =>
|
||||
wm != null &&
|
||||
!wm.Disabled)
|
||||
.ToList();
|
||||
|
||||
if (enabledMeters.Count == 0)
|
||||
return;
|
||||
|
||||
XmlPayloadRequestBuilder payloadBuilder =
|
||||
new XmlPayloadRequestBuilder(
|
||||
storageCfg);
|
||||
|
||||
PayloadGenerationRequest generationRequest =
|
||||
BuildBatchPayloadGenerationRequest(
|
||||
enabledMeters);
|
||||
|
||||
string payloadIdentifier =
|
||||
BuildBatchPayloadIdentifier(
|
||||
enabledMeters);
|
||||
|
||||
XmlPayloadBuildResult buildResult;
|
||||
|
||||
if (storageCfg.IsStoredProcedurePayloadTarget())
|
||||
{
|
||||
buildResult =
|
||||
payloadBuilder.Build(
|
||||
generationRequest,
|
||||
payloadIdentifier);
|
||||
}
|
||||
else if (storageCfg.IsXmlFileTarget())
|
||||
{
|
||||
buildResult =
|
||||
payloadBuilder.BuildFile(
|
||||
generationRequest,
|
||||
payloadIdentifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException(
|
||||
string.Format(
|
||||
"Unsupported XML payload target '{0}' / '{1}' / '{2}'.",
|
||||
storageCfg.DataStorageType,
|
||||
storageCfg.TechnologyType,
|
||||
storageCfg.WriteMode));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
buildResult.ArchiveFilePath))
|
||||
{
|
||||
log.InfoFormat(
|
||||
"XML payload archived to '{0}'.",
|
||||
buildResult.ArchiveFilePath);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
buildResult.OutputFileName))
|
||||
{
|
||||
log.InfoFormat(
|
||||
"XML batch payload generated: {0}",
|
||||
buildResult.OutputFileName);
|
||||
}
|
||||
|
||||
WriterDiagnosticResult result =
|
||||
dataStorageWriter.SetData(
|
||||
buildResult.Request);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
throw new Exception(
|
||||
result.Message);
|
||||
}
|
||||
|
||||
log.WarnFormat(
|
||||
"ResultsWriter wrote one XML payload for {0} enabled water meter(s). Target={1}, Technology={2}, Mode={3}.",
|
||||
enabledMeters.Count,
|
||||
storageCfg.DataStorageType,
|
||||
storageCfg.TechnologyType,
|
||||
storageCfg.WriteMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stable identifier used by the XML request builder for one batch.
|
||||
/// </summary>
|
||||
private string BuildBatchPayloadIdentifier(
|
||||
IList<WaterMeter> enabledMeters)
|
||||
{
|
||||
if (enabledMeters == null ||
|
||||
enabledMeters.Count == 0)
|
||||
{
|
||||
return "BATCH";
|
||||
}
|
||||
|
||||
string firstSerial =
|
||||
Convert.ToString(
|
||||
enabledMeters[0].SerialNr);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(
|
||||
firstSerial))
|
||||
{
|
||||
return "BATCH";
|
||||
}
|
||||
|
||||
return firstSerial;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a dry-run XML payload without calling the database.
|
||||
/// </summary>
|
||||
/// <param name="simulationBatch">
|
||||
/// Batch used to evaluate one-time TBF mappings.
|
||||
/// Batch used to evaluate one-time TBF mappings and provide preview context.
|
||||
/// </param>
|
||||
/// <param name="simulatedTestCount">
|
||||
/// Number of repeated GROUP/TEST instances generated for the preview.
|
||||
/// Number of logical repeated result records generated for the preview.
|
||||
/// </param>
|
||||
public XmlPayloadBuildResult GeneratePreviewPayload(
|
||||
Batch simulationBatch,
|
||||
@ -427,10 +485,70 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the legacy insert request.
|
||||
/// Writes Insert rows for one water meter using the actual TBF test context.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// One row is written for every published regular meter test.
|
||||
/// The actual test ID is passed to WMeterRsltItemSpec.Print().
|
||||
/// </remarks>
|
||||
private void WriteInsertResults(
|
||||
WaterMeter wm,
|
||||
WriterCfg storageCfg)
|
||||
{
|
||||
IList<MeterTestRslt> publishedTests =
|
||||
wm.RegularMeterTestRslts()
|
||||
.Where(
|
||||
mtr =>
|
||||
mtr != null &&
|
||||
mtr.Publish() ==
|
||||
Publish.Always)
|
||||
.ToList();
|
||||
|
||||
//
|
||||
// Preserve meter/batch data even if there is no published test.
|
||||
//
|
||||
if (publishedTests.Count == 0)
|
||||
{
|
||||
DataWriteRequest fallbackRequest =
|
||||
BuildInsertRequest(
|
||||
wm,
|
||||
string.Empty);
|
||||
|
||||
WriteInsertRequest(
|
||||
wm,
|
||||
string.Empty,
|
||||
fallbackRequest,
|
||||
storageCfg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (MeterTestRslt mtr
|
||||
in publishedTests)
|
||||
{
|
||||
string testId =
|
||||
mtr.Name() ??
|
||||
string.Empty;
|
||||
|
||||
DataWriteRequest request =
|
||||
BuildInsertRequest(
|
||||
wm,
|
||||
testId);
|
||||
|
||||
WriteInsertRequest(
|
||||
wm,
|
||||
testId,
|
||||
request,
|
||||
storageCfg);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds one Insert request for one water meter and one concrete test.
|
||||
/// </summary>
|
||||
private DataWriteRequest BuildInsertRequest(
|
||||
WaterMeter wm)
|
||||
WaterMeter wm,
|
||||
string testId)
|
||||
{
|
||||
DataWriteRequest request =
|
||||
new DataWriteRequest
|
||||
@ -441,7 +559,7 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
if (resultsWriterCfg.SelectedItems == null)
|
||||
return request;
|
||||
|
||||
foreach (var item
|
||||
foreach (Results.WMeterRsltItemSpec item
|
||||
in resultsWriterCfg.SelectedItems)
|
||||
{
|
||||
if (item == null ||
|
||||
@ -458,7 +576,9 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
item.Caption,
|
||||
|
||||
Value =
|
||||
item.Print(wm)
|
||||
item.Print(
|
||||
wm,
|
||||
testId)
|
||||
});
|
||||
}
|
||||
|
||||
@ -466,74 +586,290 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the runtime XML mapping request for one meter.
|
||||
/// Executes one prepared Insert request.
|
||||
/// </summary>
|
||||
private PayloadGenerationRequest BuildPayloadGenerationRequest(
|
||||
WaterMeter wm)
|
||||
private void WriteInsertRequest(
|
||||
WaterMeter wm,
|
||||
string testId,
|
||||
DataWriteRequest request,
|
||||
WriterCfg storageCfg)
|
||||
{
|
||||
if (request == null ||
|
||||
request.InsertItems.Count == 0)
|
||||
{
|
||||
log.WarnFormat(
|
||||
"No values to write for WM position {0}",
|
||||
wm.WMPosition);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WriterDiagnosticResult result =
|
||||
dataStorageWriter.SetData(
|
||||
request);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
throw new Exception(
|
||||
result.Message);
|
||||
}
|
||||
|
||||
log.WarnFormat(
|
||||
"ResultsWriter wrote WM position {0}, TestID='{1}'. Target={2}, Technology={3}, Mode={4}.",
|
||||
wm.WMPosition,
|
||||
testId,
|
||||
storageCfg.DataStorageType,
|
||||
storageCfg.TechnologyType,
|
||||
storageCfg.WriteMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates one runtime XML mapping request for the complete batch.
|
||||
/// </summary>
|
||||
/// <param name="enabledMeters">
|
||||
/// Enabled water meters that must be represented in the generated payload.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Every enabled water meter creates one logical repeat record. All
|
||||
/// destinations located inside the repeating XML prototype are populated
|
||||
/// into that same record.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// Result evaluation first uses the meter-level context. If that does not
|
||||
/// produce a value, the same result item is evaluated against the actual
|
||||
/// published measurement-test IDs in procedure order. This preserves
|
||||
/// meter-level values while also allowing test-result variables to be
|
||||
/// populated in the XML record.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
private PayloadGenerationRequest BuildBatchPayloadGenerationRequest(
|
||||
IList<WaterMeter> enabledMeters)
|
||||
{
|
||||
PayloadGenerationRequest request =
|
||||
new PayloadGenerationRequest();
|
||||
|
||||
if (resultsWriterCfg.SelectedItems == null)
|
||||
return request;
|
||||
|
||||
int sourceIndex = 0;
|
||||
|
||||
foreach (var item
|
||||
in resultsWriterCfg.SelectedItems)
|
||||
if (enabledMeters == null ||
|
||||
enabledMeters.Count == 0 ||
|
||||
resultsWriterCfg.SelectedItems == null)
|
||||
{
|
||||
if (item == null ||
|
||||
string.IsNullOrWhiteSpace(
|
||||
item.Caption))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
List<Results.WMeterRsltItemSpec> singleItems =
|
||||
resultsWriterCfg.SelectedItems
|
||||
.Where(
|
||||
item =>
|
||||
item != null &&
|
||||
!string.IsNullOrWhiteSpace(
|
||||
item.Caption) &&
|
||||
!IsRepeatDestination(
|
||||
item.Caption))
|
||||
.ToList();
|
||||
|
||||
List<Results.WMeterRsltItemSpec> repeatItems =
|
||||
resultsWriterCfg.SelectedItems
|
||||
.Where(
|
||||
item =>
|
||||
item != null &&
|
||||
!string.IsNullOrWhiteSpace(
|
||||
item.Caption) &&
|
||||
IsRepeatDestination(
|
||||
item.Caption))
|
||||
.ToList();
|
||||
|
||||
//
|
||||
// One-time XML destinations exist only once in the document.
|
||||
// Evaluate them from the first enabled water meter. This preserves
|
||||
// the existing one-time mapping model while repeat destinations are
|
||||
// created once for every enabled water meter.
|
||||
//
|
||||
WaterMeter firstMeter =
|
||||
enabledMeters[0];
|
||||
|
||||
for (int singleIndex = 0;
|
||||
singleIndex < singleItems.Count;
|
||||
singleIndex++)
|
||||
{
|
||||
Results.WMeterRsltItemSpec item =
|
||||
singleItems[
|
||||
singleIndex];
|
||||
|
||||
string sourceKey =
|
||||
"Result." +
|
||||
sourceIndex.ToString(
|
||||
CultureInfo.InvariantCulture);
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Batch.Single.{0}",
|
||||
singleIndex);
|
||||
|
||||
sourceIndex++;
|
||||
request.SingleMappings.Add(
|
||||
new PayloadMapping
|
||||
{
|
||||
SourceKey =
|
||||
sourceKey,
|
||||
|
||||
if (IsRepeatDestination(
|
||||
item.Caption))
|
||||
DestinationPath =
|
||||
item.Caption
|
||||
});
|
||||
|
||||
request.SingleValues.SetValue(
|
||||
sourceKey,
|
||||
EvaluateXmlMappedValue(
|
||||
firstMeter,
|
||||
item));
|
||||
}
|
||||
|
||||
//
|
||||
// Every enabled water meter becomes one logical repeat record.
|
||||
//
|
||||
for (int meterIndex = 0;
|
||||
meterIndex < enabledMeters.Count;
|
||||
meterIndex++)
|
||||
{
|
||||
WaterMeter wm =
|
||||
enabledMeters[
|
||||
meterIndex];
|
||||
|
||||
PayloadRepeatRecord record =
|
||||
new PayloadRepeatRecord();
|
||||
|
||||
for (int repeatIndex = 0;
|
||||
repeatIndex < repeatItems.Count;
|
||||
repeatIndex++)
|
||||
{
|
||||
PayloadRepeatRecord record =
|
||||
new PayloadRepeatRecord();
|
||||
Results.WMeterRsltItemSpec item =
|
||||
repeatItems[
|
||||
repeatIndex];
|
||||
|
||||
string sourceKey =
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Batch.Repeat.{0}.{1}",
|
||||
meterIndex,
|
||||
repeatIndex);
|
||||
|
||||
AddRecordMapping(
|
||||
record,
|
||||
sourceKey,
|
||||
item.Caption,
|
||||
item.Print(wm));
|
||||
EvaluateXmlMappedValue(
|
||||
wm,
|
||||
item));
|
||||
}
|
||||
|
||||
if (record.Mappings.Count > 0)
|
||||
{
|
||||
request.RepeatRecords.Add(
|
||||
record);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.SingleMappings.Add(
|
||||
new PayloadMapping
|
||||
{
|
||||
SourceKey =
|
||||
sourceKey,
|
||||
|
||||
DestinationPath =
|
||||
item.Caption
|
||||
});
|
||||
|
||||
request.SingleValues.SetValue(
|
||||
sourceKey,
|
||||
item.Print(wm));
|
||||
}
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a preview request with an exact number of simulated tests.
|
||||
/// Evaluates one configured result item for XML output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Meter/batch variables normally return a value directly from
|
||||
/// Print(wm). Test-result variables require a concrete test ID. For those
|
||||
/// variables the method evaluates the published regular meter tests in
|
||||
/// measurement-procedure order and uses the first non-empty value.
|
||||
///
|
||||
/// This fallback is intentionally applied only when the meter-level
|
||||
/// evaluation is empty.
|
||||
/// </remarks>
|
||||
private string EvaluateXmlMappedValue(
|
||||
WaterMeter wm,
|
||||
Results.WMeterRsltItemSpec item)
|
||||
{
|
||||
if (wm == null ||
|
||||
item == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string meterValue =
|
||||
item.Print(
|
||||
wm);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(
|
||||
meterValue))
|
||||
{
|
||||
return meterValue;
|
||||
}
|
||||
|
||||
IList<MeterTestRslt> publishedTests =
|
||||
wm.RegularMeterTestRslts()
|
||||
.Where(
|
||||
mtr =>
|
||||
mtr != null &&
|
||||
mtr.Publish() ==
|
||||
Publish.Always)
|
||||
.ToList();
|
||||
|
||||
string firstResolvedValue =
|
||||
string.Empty;
|
||||
|
||||
string firstResolvedTestId =
|
||||
string.Empty;
|
||||
|
||||
foreach (MeterTestRslt mtr
|
||||
in publishedTests)
|
||||
{
|
||||
string testId =
|
||||
mtr.Name() ??
|
||||
string.Empty;
|
||||
|
||||
string testValue =
|
||||
item.Print(
|
||||
wm,
|
||||
testId);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(
|
||||
testValue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(
|
||||
firstResolvedValue))
|
||||
{
|
||||
firstResolvedValue =
|
||||
testValue;
|
||||
|
||||
firstResolvedTestId =
|
||||
testId;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// A single XML destination can hold only one scalar value.
|
||||
// If more than one test produces a different value for the same
|
||||
// mapped result, preserve deterministic procedure order and keep
|
||||
// the first value, but make the ambiguity visible in the log.
|
||||
//
|
||||
if (!string.Equals(
|
||||
firstResolvedValue,
|
||||
testValue,
|
||||
StringComparison.Ordinal))
|
||||
{
|
||||
log.WarnFormat(
|
||||
"XML mapping '{0}' produced values in more than one test context for WM position {1}. Using first test '{2}'.",
|
||||
item.Caption,
|
||||
wm.WMPosition,
|
||||
firstResolvedTestId);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return firstResolvedValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a preview request with an exact number of simulated repeat records.
|
||||
/// </summary>
|
||||
private PayloadGenerationRequest BuildPreviewGenerationRequest(
|
||||
WaterMeter wm,
|
||||
@ -563,10 +899,9 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
item.Caption))
|
||||
{
|
||||
//
|
||||
// Repeated XML attributes have no predefined semantics.
|
||||
// Keep the selected TBF result exactly as configured:
|
||||
// its evaluated value is written only to its selected
|
||||
// repeating destination.
|
||||
// A repeating mapping defines a destination inside the
|
||||
// repeat prototype. The mapping itself must not create a
|
||||
// separate repeat record.
|
||||
//
|
||||
repeatItems.Add(
|
||||
item);
|
||||
@ -584,11 +919,9 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
wm);
|
||||
|
||||
//
|
||||
// A minimal simulation batch does not contain every
|
||||
// possible TBF result source. Never leave a configured
|
||||
// preview destination empty only because its runtime
|
||||
// simulation source is unavailable. Use a valid,
|
||||
// type-appropriate and clearly synthetic value instead.
|
||||
// A minimal simulation batch does not contain every possible
|
||||
// TBF result source. Use a clearly synthetic type-appropriate
|
||||
// value when the evaluated preview value is unavailable.
|
||||
//
|
||||
if (string.IsNullOrWhiteSpace(
|
||||
previewValue))
|
||||
@ -617,25 +950,38 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
}
|
||||
}
|
||||
|
||||
if (repeatItems.Count > 0)
|
||||
//
|
||||
// Create the requested number of logical repeat records. Every record
|
||||
// receives all configured repeating mappings, so one simulated record
|
||||
// is structurally equivalent to one generated runtime record.
|
||||
//
|
||||
for (int recordIndex = 0;
|
||||
recordIndex < simulatedTestCount &&
|
||||
repeatItems.Count > 0;
|
||||
recordIndex++)
|
||||
{
|
||||
for (int testIndex = 0;
|
||||
testIndex < simulatedTestCount;
|
||||
testIndex++)
|
||||
PayloadRepeatRecord record =
|
||||
new PayloadRepeatRecord();
|
||||
|
||||
for (int repeatIndex = 0;
|
||||
repeatIndex < repeatItems.Count;
|
||||
repeatIndex++)
|
||||
{
|
||||
Results.WMeterRsltItemSpec item =
|
||||
repeatItems[
|
||||
testIndex %
|
||||
repeatItems.Count];
|
||||
|
||||
PayloadRepeatRecord record =
|
||||
new PayloadRepeatRecord();
|
||||
repeatIndex];
|
||||
|
||||
string sourceKey =
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"Preview.Repeat.{0}",
|
||||
testIndex);
|
||||
"Preview.Repeat.{0}.{1}",
|
||||
recordIndex,
|
||||
repeatIndex);
|
||||
|
||||
int simulationValueIndex =
|
||||
recordIndex *
|
||||
repeatItems.Count +
|
||||
repeatIndex;
|
||||
|
||||
AddRecordMapping(
|
||||
record,
|
||||
@ -643,11 +989,11 @@ namespace TBF.Rig.Output.DB.ResultsWriter
|
||||
item.Caption,
|
||||
CreateUniversalSimulationValue(
|
||||
item,
|
||||
testIndex));
|
||||
|
||||
request.RepeatRecords.Add(
|
||||
record);
|
||||
simulationValueIndex));
|
||||
}
|
||||
|
||||
request.RepeatRecords.Add(
|
||||
record);
|
||||
}
|
||||
|
||||
return request;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user