feat: Implementato sistema Pre-Discovery con supporto esecuzioni schedulate
- Fix FindEntitiesByKeysAsync: SOQL query universale al posto di External ID GET * Disabilitato External ID GET (funziona solo per campi marcati External ID) * Query SOQL come metodo primario funzionante per tutti i campi * Logging dettagliato per diagnostica ricerche Salesforce - Pre-Discovery nei trasferimenti manuali (DataCoupler.razor.cs) * Ricerca automatica nella destinazione quando KeyAssociation non esiste * Creazione associazione con marker CreatedBy="PreDiscovery" * Aggiornamento forzato senza controllo hash per associazioni Pre-Discovery * Supporto parallel processing thread-safe - Pre-Discovery nei trasferimenti schedulati (ScheduledProfileExecutionService.cs) * Logica identica a trasferimenti manuali * Marker aggiuntivo ScheduledTransfer=true per tracciabilità * Aggiornamento forzato per prima sincronizzazione - Sistema aggiornamento forzato * Verifica AdditionalInfo per identificare associazioni Pre-Discovery * Skip controllo hash per associazioni appena scoperte * Garantisce sincronizzazione dati al primo trasferimento Vantaggi: - Prevenzione automatica duplicati in Salesforce - Recupero record esistenti senza associazioni - Parità funzionale tra esecuzioni manuali e schedulate - Performance ottimizzate con controllo hash per esecuzioni successive Docs: PRE_DISCOVERY_SYSTEM.md, PRE_DISCOVERY_FORCED_UPDATE.md, SALESFORCE_FIND_ENTITIES_FIX.md
This commit is contained in:
@@ -1312,6 +1312,104 @@ public partial class DataCoupler : ComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
// 🔍 PRE-DISCOVERY: Se non esiste associazione, cerca nella destinazione
|
||||
if (existingAssociation == null)
|
||||
{
|
||||
Logger.LogInformation("PRE-DISCOVERY: Nessuna associazione trovata per '{KeyValue}'. Cerco nella destinazione...", sourceKey);
|
||||
|
||||
// Cerca il campo destinazione mappato al campo chiave sorgente
|
||||
if (fieldMappings.TryGetValue(sourceKeyField, out var mappedDestinationFieldName))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Prepara i campi di ricerca: usa il campo mappato + il valore della chiave
|
||||
var searchFields = new Dictionary<string, object>
|
||||
{
|
||||
{ mappedDestinationFieldName, sourceKey }
|
||||
};
|
||||
|
||||
Logger.LogInformation("PRE-DISCOVERY: Cerco in '{Entity}' dove {Field} = '{Value}'",
|
||||
selectedRestEntity.Name, mappedDestinationFieldName, sourceKey);
|
||||
|
||||
// Cerca nella destinazione REST
|
||||
var existingEntities = await currentRestClient.FindEntitiesByKeysAsync(
|
||||
selectedRestEntity.Name, searchFields);
|
||||
|
||||
Logger.LogInformation("PRE-DISCOVERY: Risultati ricerca: {Count} entità trovate", existingEntities?.Count ?? 0);
|
||||
|
||||
if (existingEntities != null && existingEntities.Count > 0)
|
||||
{
|
||||
// Trovato! Prendi il primo risultato
|
||||
var foundEntity = existingEntities[0];
|
||||
|
||||
Logger.LogInformation("PRE-DISCOVERY: Campi entità trovata: {Fields}",
|
||||
string.Join(", ", foundEntity.Keys));
|
||||
|
||||
// Estrai l'ID del record trovato
|
||||
var destinationId = foundEntity.ContainsKey("Id")
|
||||
? foundEntity["Id"]?.ToString()
|
||||
: foundEntity.ContainsKey("id")
|
||||
? foundEntity["id"]?.ToString()
|
||||
: null;
|
||||
|
||||
if (!string.IsNullOrEmpty(destinationId))
|
||||
{
|
||||
Logger.LogInformation("PRE-DISCOVERY: ✅ Trovato record esistente! KeyValue: '{KeyValue}' -> DestinationId: '{DestinationId}'",
|
||||
sourceKey, destinationId);
|
||||
|
||||
// Crea l'associazione prima di procedere
|
||||
var destinationKeyField = GetEntityIdField();
|
||||
var newAssociation = new CredentialManager.Models.KeyAssociation
|
||||
{
|
||||
KeyValue = sourceKey,
|
||||
SourceKeyField = sourceKeyField,
|
||||
DestinationKeyField = destinationKeyField,
|
||||
MappedDestinationField = mappedDestinationFieldName,
|
||||
DestinationEntity = selectedRestEntity.Name,
|
||||
DestinationId = destinationId,
|
||||
RestCredentialName = selectedRestCredential,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
LastVerifiedAt = DateTime.UtcNow,
|
||||
IsActive = true,
|
||||
AdditionalInfo = System.Text.Json.JsonSerializer.Serialize(new
|
||||
{
|
||||
CreatedBy = "PreDiscovery",
|
||||
DiscoveredAt = DateTime.UtcNow,
|
||||
MappingCount = fieldMappings.Count,
|
||||
SourceType = selectedSourceType
|
||||
})
|
||||
};
|
||||
|
||||
// Salva l'associazione
|
||||
var associationId = await CredentialService.SaveKeyAssociationAsync(newAssociation);
|
||||
Logger.LogInformation("PRE-DISCOVERY: Associazione creata con ID: {AssociationId}", associationId);
|
||||
|
||||
// Usa l'associazione appena creata per il resto del flusso
|
||||
existingAssociation = newAssociation;
|
||||
existingAssociation.Id = associationId;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogWarning("PRE-DISCOVERY: Record trovato ma senza ID valido per KeyValue: '{KeyValue}'", sourceKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogInformation("PRE-DISCOVERY: Nessun record esistente trovato per KeyValue: '{KeyValue}'", sourceKey);
|
||||
}
|
||||
}
|
||||
catch (Exception discEx)
|
||||
{
|
||||
Logger.LogWarning(discEx, "PRE-DISCOVERY: Errore durante la ricerca nella destinazione per KeyValue: '{KeyValue}'", sourceKey);
|
||||
// Continua comunque, il record verrà creato normalmente
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogWarning("PRE-DISCOVERY: Campo chiave '{SourceKeyField}' non trovato nei mappings. Skip discovery.", sourceKeyField);
|
||||
}
|
||||
}
|
||||
|
||||
Logger.LogInformation("ASSOCIATION DEBUG: Associazione finale: {Found}. ID: {AssociationId}, DestinationId: '{DestinationId}', IsActive: {IsActive}",
|
||||
existingAssociation != null, existingAssociation?.Id, existingAssociation?.DestinationId, existingAssociation?.IsActive);
|
||||
|
||||
@@ -2594,6 +2692,9 @@ public partial class DataCoupler : ComponentBase
|
||||
var currentEntityName = selectedRestEntity.Name;
|
||||
var currentCredentialName = selectedRestCredential;
|
||||
var currentUseRecordAssociations = useRecordAssociations;
|
||||
var currentSourceKeyField = sourceKeyField; // Cattura il campo chiave per uso parallelo
|
||||
var currentRestClient = this.currentRestClient; // Cattura il client REST
|
||||
var currentFieldMappings = new Dictionary<string, string>(fieldMappings); // Copia dei mappings
|
||||
|
||||
// Crea lista indicizzata per mantenere il record number
|
||||
var indexedRecords = records.Select((record, index) => new { Record = record, RecordNumber = index + 1 }).ToList();
|
||||
@@ -2642,24 +2743,147 @@ public partial class DataCoupler : ComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
if (existingAssociation != null && existingAssociation.IsActive)
|
||||
// 🔍 PRE-DISCOVERY: Se non esiste associazione, cerca nella destinazione
|
||||
if (existingAssociation == null)
|
||||
{
|
||||
// CONTROLLO HASH: Verifica se i dati sono cambiati
|
||||
var existingHash = existingAssociation.Data_Hash;
|
||||
Logger.LogInformation("PRE-DISCOVERY: Nessuna associazione trovata per '{KeyValue}'. Cerco nella destinazione...", sourceKey);
|
||||
|
||||
if (!string.IsNullOrEmpty(existingHash) && existingHash.Equals(currentDataHash, StringComparison.OrdinalIgnoreCase))
|
||||
// Cerca il campo destinazione mappato al campo chiave sorgente
|
||||
if (currentFieldMappings.TryGetValue(currentSourceKeyField, out var mappedDestinationFieldName))
|
||||
{
|
||||
// I dati non sono cambiati, salta questo record
|
||||
recordsSkipped.Add((record, recordNumber, "Dati non modificati (hash identico)"));
|
||||
Logger.LogDebug("COMPOSITE PARALLEL: Record {RecordNumber} saltato - hash identico: {Hash}",
|
||||
recordNumber, currentDataHash);
|
||||
try
|
||||
{
|
||||
// Prepara i campi di ricerca: usa il campo mappato + il valore della chiave
|
||||
var searchFields = new Dictionary<string, object>
|
||||
{
|
||||
{ mappedDestinationFieldName, sourceKey }
|
||||
};
|
||||
|
||||
Logger.LogInformation("PRE-DISCOVERY: Cerco in '{Entity}' dove {Field} = '{Value}'",
|
||||
currentEntityName, mappedDestinationFieldName, sourceKey);
|
||||
|
||||
// Cerca nella destinazione REST
|
||||
var existingEntities = await currentRestClient.FindEntitiesByKeysAsync(
|
||||
currentEntityName, searchFields);
|
||||
|
||||
if (existingEntities != null && existingEntities.Count > 0)
|
||||
{
|
||||
// Trovato! Prendi il primo risultato
|
||||
var foundEntity = existingEntities[0];
|
||||
|
||||
// Estrai l'ID del record trovato
|
||||
var destinationId = foundEntity.ContainsKey("Id")
|
||||
? foundEntity["Id"]?.ToString()
|
||||
: foundEntity.ContainsKey("id")
|
||||
? foundEntity["id"]?.ToString()
|
||||
: null;
|
||||
|
||||
if (!string.IsNullOrEmpty(destinationId))
|
||||
{
|
||||
Logger.LogInformation("PRE-DISCOVERY: ✅ Trovato record esistente! KeyValue: '{KeyValue}' -> DestinationId: '{DestinationId}'",
|
||||
sourceKey, destinationId);
|
||||
|
||||
// Crea l'associazione prima di procedere
|
||||
var destinationKeyField = GetEntityIdField();
|
||||
var newAssociation = new CredentialManager.Models.KeyAssociation
|
||||
{
|
||||
KeyValue = sourceKey,
|
||||
SourceKeyField = currentSourceKeyField,
|
||||
DestinationKeyField = destinationKeyField,
|
||||
MappedDestinationField = mappedDestinationFieldName,
|
||||
DestinationEntity = currentEntityName,
|
||||
DestinationId = destinationId,
|
||||
RestCredentialName = currentCredentialName,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
LastVerifiedAt = DateTime.UtcNow,
|
||||
IsActive = true,
|
||||
Data_Hash = currentDataHash,
|
||||
AdditionalInfo = System.Text.Json.JsonSerializer.Serialize(new
|
||||
{
|
||||
CreatedBy = "PreDiscovery",
|
||||
DiscoveredAt = DateTime.UtcNow,
|
||||
MappingCount = currentFieldMappings.Count
|
||||
})
|
||||
};
|
||||
|
||||
// Salva l'associazione (metodo parallelo thread-safe)
|
||||
var associationId = await CredentialService.SaveKeyAssociationParallelAsync(newAssociation);
|
||||
Logger.LogInformation("PRE-DISCOVERY: Associazione creata con ID: {AssociationId}", associationId);
|
||||
|
||||
// Usa l'associazione appena creata per il resto del flusso
|
||||
existingAssociation = newAssociation;
|
||||
existingAssociation.Id = associationId;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogWarning("PRE-DISCOVERY: Record trovato ma senza ID valido per KeyValue: '{KeyValue}'", sourceKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogInformation("PRE-DISCOVERY: Nessun record esistente trovato per KeyValue: '{KeyValue}'", sourceKey);
|
||||
}
|
||||
}
|
||||
catch (Exception discEx)
|
||||
{
|
||||
Logger.LogWarning(discEx, "PRE-DISCOVERY: Errore durante la ricerca nella destinazione per KeyValue: '{KeyValue}'", sourceKey);
|
||||
// Continua comunque, il record verrà creato normalmente
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// I dati sono cambiati o l'hash è vuoto, procedi con l'aggiornamento
|
||||
Logger.LogWarning("PRE-DISCOVERY: Campo chiave '{SourceKeyField}' non trovato nei mappings. Skip discovery.", currentSourceKeyField);
|
||||
}
|
||||
}
|
||||
|
||||
if (existingAssociation != null && existingAssociation.IsActive)
|
||||
{
|
||||
// Verifica se l'associazione è stata creata dal Pre-Discovery
|
||||
var isPreDiscoveryAssociation = false;
|
||||
if (!string.IsNullOrEmpty(existingAssociation.AdditionalInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
var additionalInfo = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(existingAssociation.AdditionalInfo);
|
||||
if (additionalInfo != null && additionalInfo.ContainsKey("CreatedBy"))
|
||||
{
|
||||
var createdBy = additionalInfo["CreatedBy"]?.ToString();
|
||||
isPreDiscoveryAssociation = createdBy == "PreDiscovery";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignora errori di parsing
|
||||
}
|
||||
}
|
||||
|
||||
// 🔍 PRE-DISCOVERY: Se l'associazione è stata appena creata dal Pre-Discovery, FORZA l'aggiornamento
|
||||
if (isPreDiscoveryAssociation)
|
||||
{
|
||||
// Forza aggiornamento senza controllo hash
|
||||
recordsForUpdate.Add((restData, existingAssociation.DestinationId, record, recordNumber, currentDataHash));
|
||||
Logger.LogDebug("COMPOSITE PARALLEL: Record {RecordNumber} marcato per aggiornamento (EntityId: {EntityId}) - hash diverso: old={OldHash}, new={NewHash}",
|
||||
recordNumber, existingAssociation.DestinationId, existingHash ?? "NULL", currentDataHash);
|
||||
Logger.LogInformation("COMPOSITE PARALLEL: Record {RecordNumber} marcato per AGGIORNAMENTO FORZATO (Pre-Discovery) - EntityId: {EntityId}",
|
||||
recordNumber, existingAssociation.DestinationId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CONTROLLO HASH: Verifica se i dati sono cambiati (solo per associazioni esistenti)
|
||||
var existingHash = existingAssociation.Data_Hash;
|
||||
|
||||
if (!string.IsNullOrEmpty(existingHash) && existingHash.Equals(currentDataHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// I dati non sono cambiati, salta questo record
|
||||
recordsSkipped.Add((record, recordNumber, "Dati non modificati (hash identico)"));
|
||||
Logger.LogDebug("COMPOSITE PARALLEL: Record {RecordNumber} saltato - hash identico: {Hash}",
|
||||
recordNumber, currentDataHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
// I dati sono cambiati o l'hash è vuoto, procedi con l'aggiornamento
|
||||
recordsForUpdate.Add((restData, existingAssociation.DestinationId, record, recordNumber, currentDataHash));
|
||||
Logger.LogDebug("COMPOSITE PARALLEL: Record {RecordNumber} marcato per aggiornamento (EntityId: {EntityId}) - hash diverso: old={OldHash}, new={NewHash}",
|
||||
recordNumber, existingAssociation.DestinationId, existingHash ?? "NULL", currentDataHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -534,24 +534,147 @@ public class ScheduledProfileExecutionService : IScheduledProfileExecutionServic
|
||||
}
|
||||
}
|
||||
|
||||
if (existingAssociation != null && existingAssociation.IsActive)
|
||||
// 🔍 PRE-DISCOVERY: Se non esiste associazione, cerca nella destinazione
|
||||
if (existingAssociation == null && !string.IsNullOrEmpty(profile.SourceKeyField))
|
||||
{
|
||||
// CONTROLLO HASH: Verifica se i dati sono cambiati
|
||||
var existingHash = existingAssociation.Data_Hash;
|
||||
_logger.LogInformation("PRE-DISCOVERY SCHEDULED: Nessuna associazione trovata per '{KeyValue}'. Cerco nella destinazione...", sourceKey);
|
||||
|
||||
if (!string.IsNullOrEmpty(existingHash) && existingHash.Equals(currentDataHash, StringComparison.OrdinalIgnoreCase))
|
||||
// Cerca il campo destinazione mappato al campo chiave sorgente
|
||||
if (fieldMappings.TryGetValue(profile.SourceKeyField, out var mappedDestinationFieldName))
|
||||
{
|
||||
// I dati non sono cambiati, salta questo record
|
||||
recordsSkipped.Add((record, recordNumber, "Dati non modificati (hash identico)"));
|
||||
_logger.LogDebug("COMPOSITE SCHEDULED: Record {RecordNumber} saltato - hash identico: {Hash}",
|
||||
recordNumber, currentDataHash);
|
||||
try
|
||||
{
|
||||
// Prepara i campi di ricerca: usa il campo mappato + il valore della chiave
|
||||
var searchFields = new Dictionary<string, object>
|
||||
{
|
||||
{ mappedDestinationFieldName, sourceKey }
|
||||
};
|
||||
|
||||
_logger.LogInformation("PRE-DISCOVERY SCHEDULED: Cerco in '{Entity}' dove {Field} = '{Value}'",
|
||||
currentEntityName, mappedDestinationFieldName, sourceKey);
|
||||
|
||||
// Cerca nella destinazione REST
|
||||
var existingEntities = await restClient.FindEntitiesByKeysAsync(
|
||||
currentEntityName, searchFields);
|
||||
|
||||
if (existingEntities != null && existingEntities.Count > 0)
|
||||
{
|
||||
// Trovato! Prendi il primo risultato
|
||||
var foundEntity = existingEntities[0];
|
||||
|
||||
// Estrai l'ID del record trovato
|
||||
var destinationId = foundEntity.ContainsKey("Id")
|
||||
? foundEntity["Id"]?.ToString()
|
||||
: foundEntity.ContainsKey("id")
|
||||
? foundEntity["id"]?.ToString()
|
||||
: null;
|
||||
|
||||
if (!string.IsNullOrEmpty(destinationId))
|
||||
{
|
||||
_logger.LogInformation("PRE-DISCOVERY SCHEDULED: ✅ Trovato record esistente! KeyValue: '{KeyValue}' -> DestinationId: '{DestinationId}'",
|
||||
sourceKey, destinationId);
|
||||
|
||||
// Crea l'associazione prima di procedere
|
||||
var newAssociation = new KeyAssociation
|
||||
{
|
||||
KeyValue = sourceKey,
|
||||
SourceKeyField = profile.SourceKeyField,
|
||||
DestinationKeyField = "Id",
|
||||
MappedDestinationField = mappedDestinationFieldName,
|
||||
DestinationEntity = currentEntityName,
|
||||
DestinationId = destinationId,
|
||||
RestCredentialName = currentCredentialName,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
LastVerifiedAt = DateTime.UtcNow,
|
||||
IsActive = true,
|
||||
Data_Hash = currentDataHash,
|
||||
AdditionalInfo = JsonSerializer.Serialize(new
|
||||
{
|
||||
CreatedBy = "PreDiscovery",
|
||||
DiscoveredAt = DateTime.UtcNow,
|
||||
MappingCount = fieldMappings.Count,
|
||||
ScheduledTransfer = true
|
||||
})
|
||||
};
|
||||
|
||||
// Salva l'associazione (metodo parallelo thread-safe)
|
||||
var associationId = await _dataConnectionCredentialService.SaveKeyAssociationParallelAsync(newAssociation);
|
||||
_logger.LogInformation("PRE-DISCOVERY SCHEDULED: Associazione creata con ID: {AssociationId}", associationId);
|
||||
|
||||
// Usa l'associazione appena creata per il resto del flusso
|
||||
existingAssociation = newAssociation;
|
||||
existingAssociation.Id = associationId;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("PRE-DISCOVERY SCHEDULED: Record trovato ma senza ID valido per KeyValue: '{KeyValue}'", sourceKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("PRE-DISCOVERY SCHEDULED: Nessun record esistente trovato per KeyValue: '{KeyValue}'", sourceKey);
|
||||
}
|
||||
}
|
||||
catch (Exception discEx)
|
||||
{
|
||||
_logger.LogWarning(discEx, "PRE-DISCOVERY SCHEDULED: Errore durante la ricerca nella destinazione per KeyValue: '{KeyValue}'", sourceKey);
|
||||
// Continua comunque, il record verrà creato normalmente
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// I dati sono cambiati o l'hash è vuoto, procedi con l'aggiornamento
|
||||
_logger.LogWarning("PRE-DISCOVERY SCHEDULED: Campo chiave '{SourceKeyField}' non trovato nei mappings. Skip discovery.", profile.SourceKeyField);
|
||||
}
|
||||
}
|
||||
|
||||
if (existingAssociation != null && existingAssociation.IsActive)
|
||||
{
|
||||
// Verifica se l'associazione è stata creata dal Pre-Discovery
|
||||
var isPreDiscoveryAssociation = false;
|
||||
if (!string.IsNullOrEmpty(existingAssociation.AdditionalInfo))
|
||||
{
|
||||
try
|
||||
{
|
||||
var additionalInfo = JsonSerializer.Deserialize<Dictionary<string, object>>(existingAssociation.AdditionalInfo);
|
||||
if (additionalInfo != null && additionalInfo.ContainsKey("CreatedBy"))
|
||||
{
|
||||
var createdBy = additionalInfo["CreatedBy"]?.ToString();
|
||||
isPreDiscoveryAssociation = createdBy == "PreDiscovery";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignora errori di parsing
|
||||
}
|
||||
}
|
||||
|
||||
// 🔍 PRE-DISCOVERY: Se l'associazione è stata appena creata dal Pre-Discovery, FORZA l'aggiornamento
|
||||
if (isPreDiscoveryAssociation)
|
||||
{
|
||||
// Forza aggiornamento senza controllo hash
|
||||
recordsForUpdate.Add((restData, existingAssociation.DestinationId, record, recordNumber, currentDataHash));
|
||||
_logger.LogDebug("COMPOSITE SCHEDULED: Record {RecordNumber} marcato per aggiornamento (EntityId: {EntityId}) - hash diverso: old={OldHash}, new={NewHash}",
|
||||
recordNumber, existingAssociation.DestinationId, existingHash ?? "NULL", currentDataHash);
|
||||
_logger.LogInformation("COMPOSITE SCHEDULED: Record {RecordNumber} marcato per AGGIORNAMENTO FORZATO (Pre-Discovery) - EntityId: {EntityId}",
|
||||
recordNumber, existingAssociation.DestinationId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CONTROLLO HASH: Verifica se i dati sono cambiati (solo per associazioni esistenti)
|
||||
var existingHash = existingAssociation.Data_Hash;
|
||||
|
||||
if (!string.IsNullOrEmpty(existingHash) && existingHash.Equals(currentDataHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// I dati non sono cambiati, salta questo record
|
||||
recordsSkipped.Add((record, recordNumber, "Dati non modificati (hash identico)"));
|
||||
_logger.LogDebug("COMPOSITE SCHEDULED: Record {RecordNumber} saltato - hash identico: {Hash}",
|
||||
recordNumber, currentDataHash);
|
||||
}
|
||||
else
|
||||
{
|
||||
// I dati sono cambiati o l'hash è vuoto, procedi con l'aggiornamento
|
||||
recordsForUpdate.Add((restData, existingAssociation.DestinationId, record, recordNumber, currentDataHash));
|
||||
_logger.LogDebug("COMPOSITE SCHEDULED: Record {RecordNumber} marcato per aggiornamento (EntityId: {EntityId}) - hash diverso: old={OldHash}, new={NewHash}",
|
||||
recordNumber, existingAssociation.DestinationId, existingHash ?? "NULL", currentDataHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user