- 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
8.3 KiB
Fix MappedDestinationField Non Salvato nel Database
🐛 Problema Identificato
Il campo MappedDestinationField veniva popolato correttamente nell'oggetto KeyAssociation ma non veniva scritto nel database.
Causa Root
Il metodo SaveAssociationParallelAsync in KeyAssociationService.cs utilizzava query SQL raw che non includevano il campo MappedDestinationField né nell'UPDATE né nell'INSERT.
✅ Correzione Implementata
File Modificato
CredentialManager/Services/KeyAssociationService.cs
Metodo: SaveAssociationParallelAsync (linea ~159)
1. Aggiunta Cattura del Valore
var mappedDestinationField = association.MappedDestinationField; // AGGIUNTO
2. Query UPDATE Corretta
Prima:
UPDATE KeyAssociations
SET DestinationId = {0},
SourceKeyField = {1},
DestinationKeyField = {2},
UpdatedAt = {3},
LastVerifiedAt = {4},
AdditionalInfo = {5},
Data_Hash = {6}
WHERE KeyValue = {7}
AND DestinationEntity = {8}
AND RestCredentialName = {9}
AND IsActive = 1
Dopo:
UPDATE KeyAssociations
SET DestinationId = {0},
SourceKeyField = {1},
DestinationKeyField = {2},
UpdatedAt = {3},
LastVerifiedAt = {4},
AdditionalInfo = {5},
Data_Hash = {6},
MappedDestinationField = {7} ← AGGIUNTO
WHERE KeyValue = {8} ← Indici aggiornati
AND DestinationEntity = {9} ← Indici aggiornati
AND RestCredentialName = {10} ← Indici aggiornati
AND IsActive = 1
Parametri aggiornati:
destinationId,
sourceKeyField,
destinationKeyField,
currentTime,
currentTime,
additionalInfo ?? (object)DBNull.Value,
dataHash ?? (object)DBNull.Value,
mappedDestinationField ?? (object)DBNull.Value, // AGGIUNTO
keyValue,
destinationEntity,
restCredentialName
3. INSERT Corretto (Entity Framework)
Prima:
var newAssociation = new KeyAssociation
{
KeyValue = keyValue,
SourceKeyField = sourceKeyField,
DestinationKeyField = destinationKeyField,
// MappedDestinationField mancante!
DestinationEntity = destinationEntity,
DestinationId = destinationId,
// ...
};
Dopo:
var newAssociation = new KeyAssociation
{
KeyValue = keyValue,
SourceKeyField = sourceKeyField,
DestinationKeyField = destinationKeyField,
MappedDestinationField = mappedDestinationField, // AGGIUNTO
DestinationEntity = destinationEntity,
DestinationId = destinationId,
// ...
};
4. Logging Migliorato
Prima:
_logger.LogDebug("PARALLEL: Tentativo salvataggio associazione - KeyValue: '{KeyValue}', DestinationEntity: '{DestinationEntity}', DestinationId: '{DestinationId}', RestCredentialName: '{RestCredentialName}'",
keyValue, destinationEntity, destinationId, restCredentialName);
Dopo:
_logger.LogDebug("PARALLEL: Tentativo salvataggio associazione - KeyValue: '{KeyValue}', DestinationEntity: '{DestinationEntity}', DestinationId: '{DestinationId}', RestCredentialName: '{RestCredentialName}', MappedField: '{MappedField}'",
keyValue, destinationEntity, destinationId, restCredentialName, mappedDestinationField ?? "NULL");
// E per il log di creazione:
_logger.LogDebug("PARALLEL: Nuova associazione creata: KeyValue={KeyValue} -> {DestinationEntity}/{DestinationId}, MappedField={MappedField}",
keyValue, destinationEntity, destinationId, mappedDestinationField ?? "NULL");
🧪 Testing
Procedura di Test
-
Fermare l'applicazione attualmente in esecuzione
-
Ricompilare il progetto:
dotnet build Data_Coupler.sln -
Riavviare l'applicazione
-
Eseguire un nuovo trasferimento dati:
- Configurare un mapping (es: Email → EmailAddress)
- Selezionare "Email" come campo chiave
- Eseguire il trasferimento
-
Verificare nei log:
PARALLEL: Tentativo salvataggio associazione - ... MappedField: 'EmailAddress' PARALLEL: Nuova associazione creata: ... MappedField: EmailAddress -
Verificare nel database:
SELECT Id, KeyValue, SourceKeyField, MappedDestinationField, -- Questo campo ora deve essere popolato! DestinationKeyField, DestinationId FROM KeyAssociations ORDER BY CreatedAt DESC LIMIT 10;
Risultato Atteso
Prima del Fix:
| Id | KeyValue | SourceKeyField | MappedDestinationField | DestinationKeyField | DestinationId |
|---|---|---|---|---|---|
| 1 | C00001 | CardCode | NULL ❌ | Id | ABC123 |
| 2 | C00026 | CardCode | NULL ❌ | Id | DEF456 |
Dopo il Fix:
| Id | KeyValue | SourceKeyField | MappedDestinationField | DestinationKeyField | DestinationId |
|---|---|---|---|---|---|
| 1 | C00001 | CardCode | EmailAddress ✅ | Id | ABC123 |
| 2 | C00026 | CardCode | EmailAddress ✅ | Id | DEF456 |
📊 Impatto della Correzione
Componenti Affetti
- ✅ Creazione nuove associazioni: Ora salva correttamente il campo
- ✅ Aggiornamento associazioni esistenti: Ora aggiorna correttamente il campo
- ✅ Logging: Ora mostra il valore nel log per debug
- ✅ UI KeyAssociations: Ora mostrerà il valore invece di "N/A"
Retrocompatibilità
✅ Completamente compatibile:
- Le associazioni esistenti (con campo NULL) continueranno a funzionare
- Le nuove associazioni avranno il campo popolato
- Nessuna migration aggiuntiva richiesta (il campo è già nel database)
🔍 Spiegazione Tecnica
Perché il Campo Non Veniva Salvato?
Il metodo SaveAssociationParallelAsync usa un pattern di upsert ottimizzato per gestire race conditions in operazioni parallele:
- Primo tentativo: UPDATE via SQL raw
- Se fallisce: INSERT via Entity Framework
Il problema era che:
- ❌ La query SQL raw dell'UPDATE non includeva
MappedDestinationField - ❌ L'oggetto Entity Framework dell'INSERT non assegnava
MappedDestinationField
Perché Usare SQL Raw?
// SQL Raw per UPDATE (più performante e thread-safe)
await parallelContext.Database.ExecuteSqlRawAsync(@"UPDATE ...");
// Entity Framework per INSERT (più semplice per gestire race conditions)
parallelContext.KeyAssociations.Add(newAssociation);
await parallelContext.SaveChangesAsync();
Vantaggi:
- Performance migliori per UPDATE
- Gestione automatica race conditions per INSERT
- Thread-safe con DbContext separati
✅ Checklist Verifica
- Campo aggiunto alla query UPDATE SQL
- Campo aggiunto all'oggetto INSERT Entity Framework
- Parametri query SQL aggiornati con indici corretti
- Logging aggiornato per includere MappedDestinationField
- Verifica assenza errori di compilazione
- Fermare applicazione
- Ricompilare progetto
- Riavviare applicazione
- Eseguire test trasferimento
- Verificare log contiene "MappedField: 'XXX'"
- Verificare database con SELECT
🎯 Prossimi Passi IMMEDIATI
- ⛔ FERMARE l'applicazione in esecuzione
- 🔨 Ricompilare:
dotnet build Data_Coupler.sln - ▶️ Riavviare l'applicazione
- 🧪 Test completo:
- Crea nuovo mapping con campo chiave
- Esegui trasferimento
- Verifica log:
"MappedField: 'EmailAddress'" - Query database per conferma
- 🗑️ Opzionale: Cancella vecchie associazioni di test (con campo NULL)
📝 Note Aggiuntive
Cancellare Associazioni Vecchie (Opzionale)
Se vuoi pulire le associazioni di test create prima del fix:
-- Mostra associazioni con campo NULL
SELECT * FROM KeyAssociations
WHERE MappedDestinationField IS NULL;
-- Cancella associazioni di test (ATTENZIONE!)
DELETE FROM KeyAssociations
WHERE MappedDestinationField IS NULL
AND CreatedAt > '2025-10-19'; -- Solo quelle create oggi
Verifica Migration Database
Se il database non ha la colonna, esegui:
cd CredentialManager
dotnet ef database update
Data Correzione: 20 Ottobre 2025
Versione: 3.0 - Fix Salvataggio Database
Status: ✅ Pronto per test - Ricompilazione richiesta