5d9b9756cf
- 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
192 lines
6.9 KiB
Markdown
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.
|