Files
Data-Coupler/MAPPED_DESTINATION_FIELD_IMPLEMENTATION.md
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

192 lines
6.9 KiB
Markdown

# 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:
```csharp
/// <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:
```csharp
// 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`:
```csharp
// 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:
```csharp
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:**
```json
{
"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
```sql
-- 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.