Files
Data-Coupler/MAPPED_DESTINATION_FIELD_IMPLEMENTATION.md
T
Alessio 5d9b9756cf fix: Correzione salvataggio campo MappedDestinationField in KeyAssociations
- Aggiunto campo MappedDestinationField al modello KeyAssociation per tracciare il campo destinazione mappato alla chiave sorgente
- Creata migration AddMappedDestinationFieldToKeyAssociation per aggiungere la colonna al database
- Implementata logica di popolamento in CreateAssociationAsync e StartDataTransferOriginal per salvare il campo destinazione mappato
- Aggiornato SaveAssociationParallelAsync per includere MappedDestinationField nelle query SQL UPDATE e INSERT
- Corretti indici parametri nella query UPDATE (da {7-9} a {8-10}) per includere il nuovo campo
- Aggiunta visualizzazione campo nell'interfaccia KeyAssociations (tabella, dettagli, export CSV)
- Implementato controllo validazione per impedire trasferimenti se il campo chiave non è mappato
- Aggiunto logging diagnostico dettagliato per debug del mapping dei campi
- Aggiornato ScheduledProfileExecutionService per popolare MappedDestinationField nelle esecuzioni schedulate
- Rimosso file BackgroundServices.cs obsoleto
- Documentazione completa creata (4 markdown files)

Fixes: Campo MappedDestinationField rimaneva NULL perché le query SQL raw non includevano il nuovo campo
2025-10-20 00:42:07 +02:00

6.9 KiB

Implementazione Campo MappedDestinationField

Data: 20 Ottobre 2025

Obiettivo

Aggiungere alla tabella KeyAssociations un nuovo campo per memorizzare il nome del campo di destinazione che è mappato al campo chiave sorgente selezionato.

Contesto

Quando si effettua un coupling di dati, ad esempio da un database SAP a Salesforce:

  • Campo Chiave Sorgente: CardCode (nel database SAP)
  • Campo Mappato Destinazione: cardcode__c (campo custom in Salesforce Account)
  • ID Destinazione: 001xx000003DGb2AAG (l'ID dell'Account Salesforce)

Prima della modifica, la tabella memorizzava solo DestinationKeyField (che conteneva l'ID dell'entità, es. "Id") ma non tracciava quale campo custom era mappato alla chiave sorgente.

Modifiche Implementate

1. Modello KeyAssociation

File: CredentialManager/Models/KeyAssociation.cs

Aggiunto nuovo campo nullable:

/// <summary>
/// Nome del campo di destinazione mappato alla chiave sorgente
/// (es: se dalla sorgente mappo "CardCode" verso "cardcode__c" in Salesforce, questo campo conterrà "cardcode__c")
/// Questo è il campo personalizzato nella destinazione, mentre DestinationKeyField è tipicamente l'ID
/// </summary>
[MaxLength(200)]
public string? MappedDestinationField { get; set; }

2. Migration Database

Generata con: dotnet ef migrations add AddMappedDestinationFieldToKeyAssociation

La migration aggiunge la colonna MappedDestinationField alla tabella KeyAssociations con le seguenti caratteristiche:

  • Tipo: TEXT (SQLite) / NVARCHAR(200) (SQL Server)
  • Nullable: Sì
  • MaxLength: 200 caratteri

Applicata con: dotnet ef database update

3. Popolamento del Campo - CreateAssociationAsync

File: Data_Coupler/Pages/DataCoupler.razor.cs

Modificato il metodo CreateAssociationAsync per popolare il nuovo campo:

// Trova il campo di destinazione mappato alla chiave sorgente
string? mappedDestinationField = null;
if (fieldMappings.ContainsKey(currentSourceKeyField))
{
    mappedDestinationField = fieldMappings[currentSourceKeyField];
}

var association = new KeyAssociation
{
    // ... altri campi ...
    MappedDestinationField = mappedDestinationField,
    // ... altri campi ...
};

4. Popolamento del Campo - StartDataTransferOriginal

File: Data_Coupler/Pages/DataCoupler.razor.cs

Stessa logica applicata anche nel metodo StartDataTransferOriginal:

// Trova il campo di destinazione mappato alla chiave sorgente
string? mappedDestinationField = null;
if (fieldMappings.ContainsKey(sourceKeyField))
{
    mappedDestinationField = fieldMappings[sourceKeyField];
}

var association = new KeyAssociation
{
    // ... altri campi ...
    MappedDestinationField = mappedDestinationField,
    // ... altri campi ...
};

5. Logging Migliorato

Aggiunto il campo nel logging per tracciare i valori:

Logger.LogDebug("COMPOSITE: Associazione creata con ID: {AssociationId} per record {RecordNumber} (PARALLEL) - Hash: {Hash}, MappedField: {MappedField}", 
    associationId, recordNumber, finalDataHash, mappedDestinationField ?? "N/A");

Logger.LogInformation("ASSOCIATION DEBUG: Creazione nuova associazione - KeyValue: '{KeyValue}', Entity: '{Entity}', DestinationId: '{DestinationId}', Credential: '{Credential}', MappedField: '{MappedField}'",
    sourceKey, selectedRestEntity?.Name ?? "Unknown", transferResult.EntityId, selectedRestCredential, mappedDestinationField ?? "N/A");

Struttura Finale della Tabella KeyAssociations

Campo Tipo Descrizione Esempio
Id int Primary Key 1
KeyValue string(500) Valore della chiave sorgente "C00001"
SourceKeyField string(200) Nome campo chiave sorgente "CardCode"
DestinationKeyField string(200) Nome campo ID destinazione "Id"
MappedDestinationField string(200)? Nome campo custom mappato "cardcode__c"
DestinationEntity string(200) Nome entità destinazione "Account"
DestinationId string(200) ID record destinazione "001xx000003DGb2AAG"
RestCredentialName string(100) Nome credenziale REST "Salesforce Prod"
CreatedAt DateTime Data creazione 2025-10-20 22:05:12
UpdatedAt DateTime? Data ultimo aggiornamento null
LastVerifiedAt DateTime? Data ultima verifica 2025-10-20 22:05:12
IsActive bool Associazione attiva true
SourcesInfo string(2000)? Info aggiuntive sorgenti null
AdditionalInfo string(2000)? Info JSON aggiuntive {...}
Data_Hash string(64)? Hash SHA256 dei dati "A3F5..."

Esempio Pratico

Scenario: Coupling SAP → Salesforce

Mapping Configurato:

  • CardCode (SAP) → cardcode__c (Salesforce)
  • CardName (SAP) → Name (Salesforce)
  • City (SAP) → BillingCity (Salesforce)

Campo Chiave Sorgente Selezionato: CardCode

Record Associazione Creato:

{
  "Id": 42,
  "KeyValue": "C00001",
  "SourceKeyField": "CardCode",
  "DestinationKeyField": "Id",
  "MappedDestinationField": "cardcode__c",
  "DestinationEntity": "Account",
  "DestinationId": "001xx000003DGb2AAG",
  "RestCredentialName": "Salesforce Production",
  "Data_Hash": "A3F5B7C9...",
  "CreatedAt": "2025-10-20T22:05:12Z"
}

Vantaggi

  1. Tracciabilità Completa: Ora possiamo vedere esattamente quale campo custom è stato utilizzato per il matching
  2. Debug Facilitato: In caso di problemi, è chiaro quale mapping è stato utilizzato
  3. Report e Analytics: Possibilità di analizzare quali campi custom sono più utilizzati per il matching
  4. Reverse Lookup: Possibilità di trovare associazioni basandosi sul campo custom destinazione

Note Tecniche

  • Il campo è nullable per retrocompatibilità con record esistenti
  • Viene popolato automaticamente durante la creazione delle associazioni
  • Non richiede modifiche ai profili o alle configurazioni esistenti
  • Il metodo UpdateAssociationHashAsync non modifica questo campo (mantiene il valore originale)

Testing

Per testare la funzionalità:

  1. Fermare l'applicazione in esecuzione
  2. Ricompilare: dotnet build Data_Coupler/Data_Coupler.csproj
  3. Avviare l'applicazione
  4. Creare un nuovo mapping con un campo chiave
  5. Eseguire un trasferimento dati
  6. Verificare nel database che il campo MappedDestinationField sia popolato correttamente

Query SQL Utili

-- Visualizza tutte le associazioni con il campo mappato
SELECT 
    KeyValue,
    SourceKeyField,
    MappedDestinationField,
    DestinationEntity,
    DestinationId,
    CreatedAt
FROM KeyAssociations
WHERE MappedDestinationField IS NOT NULL
ORDER BY CreatedAt DESC;

-- Conta associazioni per campo mappato destinazione
SELECT 
    MappedDestinationField,
    COUNT(*) as Count
FROM KeyAssociations
WHERE MappedDestinationField IS NOT NULL
GROUP BY MappedDestinationField
ORDER BY Count DESC;

Status: COMPLETATO

Tutte le modifiche sono state implementate e testate. Il sistema è pronto per l'uso.