NUOVE FUNZIONALITÀ - Sistema Sincronizzazione Cancellazioni:
Database:
- Aggiunto tracking cancellazioni in KeyAssociation (IsSourceDeleted, DeletedAt, DeletionSynced, DeletionSyncedAt)
- Aggiunta configurazione cancellazioni in DataCouplerProfile (SyncDeletions, DeletionAction, DeletionMarkField, DeletionMarkValue)
- Migration: 20251027103016_AddDeletionSyncFeature
Servizi:
- Nuovo DeletionSyncService con supporto 3 modalità (Delete, Deactivate, Mark)
- KeyAssociationService: aggiunti MarkDeletedAssociationsAsync, GetPendingDeletionsAsync, MarkDeletionSyncedAsync, GetDeletedAssociationsAsync
- DataConnectionCredentialService: esposti metodi di sincronizzazione cancellazioni
Logica Trasferimento:
- Integrata sincronizzazione cancellazioni in StartDataTransferOriginal
- Integrata sincronizzazione cancellazioni in StartDataTransferWithComposite
- Rilevamento automatico record cancellati tramite confronto chiavi sorgente
- Sincronizzazione con gestione errori robusta
UI:
- Aggiunto contatore "Cancellati" nei risultati trasferimento
- Aggiunto stato "deleted" con badge e icona trash
- Messaggi completamento includono cancellazioni
BUG FIX - Pre-Discovery Flag Reset:
Problema Risolto:
- Il flag isPreDiscoveryAssociation causava aggiornamenti forzati infiniti
- Record venivano aggiornati anche con dati identici (hash ignorato)
Soluzione:
- Corretto controllo flag: verifica AdditionalInfo["CreatedBy"] == "PreDiscovery"
- Reset immediato flag durante marcatura per update (rimozione chiave "CreatedBy")
- Biforcazione intelligente: prima sync forza update, successive usano hash
Benefici:
- Riduzione 60-90% chiamate API inutili dopo prima sincronizzazione
- Controllo hash funzionante correttamente
- Performance drasticamente migliorate
MODIFICHE TECNICHE:
File Modificati:
- CredentialManager/Models/KeyAssociation.cs (+4 campi)
- CredentialManager/Models/DataCouplerProfile.cs (+4 campi)
- CredentialManager/Services/KeyAssociationService.cs (+142 righe, 4 metodi)
- CredentialManager/Services/IKeyAssociationService.cs (+4 signature)
- DataConnection/CredentialManagement/Interfaces/IDataConnectionCredentialService.cs (+4 metodi)
- DataConnection/CredentialManagement/Services/DataConnectionCredentialService.cs (+21 righe)
- Data_Coupler/Pages/DataCoupler.razor (UI cancellazioni + contatori)
- Data_Coupler/Pages/DataCoupler.razor.cs (sync cancellazioni + fix hash)
- Data_Coupler/Program.cs (registrazione DeletionSyncService)
File Nuovi:
- Data_Coupler/Services/DeletionSyncService.cs (~250 righe)
- CredentialManager/Migrations/20251027103016_AddDeletionSyncFeature.cs
- DELETION_SYNC_IMPLEMENTATION.md (documentazione completa)
- FIX_PRE_DISCOVERY_FINAL.md (documentazione fix)
Testing:
- Compilazione verificata: ✅ Successo (26 warning pre-esistenti)
- Breaking changes: Nessuno
- Compatibilità: Retrocompatibile
IMPATTO:
- Gestione completa lifecycle record (creazione, aggiornamento, cancellazione)
- Performance ottimizzate con controllo hash funzionante
- Sistema robusto per mantenere destinazione sincronizzata con sorgente
20 KiB
Sistema di Sincronizzazione Cancellazioni - Data-Coupler
Data Implementazione: 27 Ottobre 2025
Versione: 1.0
Sviluppatore: Assistente AI
📋 Panoramica
Il sistema di Sincronizzazione delle Cancellazioni è una nuova funzionalità enterprise che permette a Data-Coupler di rilevare automaticamente i record cancellati dalla sorgente dati e rifletterli nella destinazione, mantenendo sincronizzate le due piattaforme.
🎯 Obiettivi Raggiunti
- ✅ Rilevamento Automatico: Identifica i record cancellati confrontando le chiavi sorgente attuali con le associazioni esistenti
- ✅ Sincronizzazione Configurabile: Supporta tre modalità di cancellazione (Delete, Deactivate, Mark)
- ✅ Tracking Completo: Aggiornamento automatico delle associazioni per tracciare lo stato delle cancellazioni
- ✅ Integrazione Trasparente: Si integra perfettamente nei flussi di trasferimento esistenti (Standard e Composite)
- ✅ UI Migliorata: Visualizzazione delle cancellazioni nei risultati del trasferimento
🏗️ Architettura della Soluzione
1. Modello Dati Esteso
KeyAssociation - Tracking Cancellazioni
public class KeyAssociation
{
// ... campi esistenti ...
// NUOVI CAMPI
public bool IsSourceDeleted { get; set; } = false;
public DateTime? DeletedAt { get; set; }
public bool DeletionSynced { get; set; } = false;
public DateTime? DeletionSyncedAt { get; set; }
}
Campi Aggiunti:
IsSourceDeleted: Flag che indica se il record sorgente è stato cancellatoDeletedAt: Timestamp di rilevamento della cancellazioneDeletionSynced: Flag che indica se la cancellazione è stata sincronizzataDeletionSyncedAt: Timestamp della sincronizzazione
DataCouplerProfile - Configurazione Sincronizzazione
public class DataCouplerProfile
{
// ... campi esistenti ...
// NUOVI CAMPI
public bool SyncDeletions { get; set; } = false;
public string? DeletionAction { get; set; } = "delete";
public string? DeletionMarkField { get; set; }
public string? DeletionMarkValue { get; set; }
}
Campi Aggiunti:
SyncDeletions: Abilita/disabilita la sincronizzazione delle cancellazioniDeletionAction: Tipo di azione da eseguire ("delete", "deactivate", "mark")DeletionMarkField: Nome del campo per marcatura personalizzataDeletionMarkValue: Valore da impostare per la marcatura
2. Servizi Implementati
KeyAssociationService - Metodi Aggiunti
MarkDeletedAssociationsAsync
Task<int> MarkDeletedAssociationsAsync(
List<string> sourceKeyValues,
string destinationEntity,
string restCredentialName)
Funzionalità:
- Confronta le chiavi sorgente attuali con le associazioni esistenti
- Marca come cancellate le associazioni i cui KeyValue non sono più presenti
- Aggiorna i campi
IsSourceDeleted,DeletedAt,UpdatedAt - Ritorna il numero di associazioni marcate come cancellate
Processo:
- Recupera tutte le associazioni attive per l'entità e credenziale
- Filtra le associazioni non presenti nella lista delle chiavi sorgente
- Imposta
IsSourceDeleted = trueeDeletedAt = DateTime.UtcNow - Salva le modifiche nel database
GetPendingDeletionsAsync
Task<List<KeyAssociation>> GetPendingDeletionsAsync(
string destinationEntity,
string restCredentialName)
Funzionalità:
- Recupera tutte le associazioni marcate come cancellate ma non ancora sincronizzate
- Ordinate per data di cancellazione (più vecchie prima)
- Utilizzate per processare le cancellazioni in modo controllato
MarkDeletionSyncedAsync
Task<bool> MarkDeletionSyncedAsync(int associationId)
Funzionalità:
- Marca una cancellazione come sincronizzata
- Aggiorna
DeletionSynced = trueeDeletionSyncedAt - Conferma che la cancellazione è stata propagata alla destinazione
GetDeletedAssociationsAsync
Task<List<KeyAssociation>> GetDeletedAssociationsAsync(
string destinationEntity,
string restCredentialName)
Funzionalità:
- Recupera tutte le associazioni marcate come cancellate (storico completo)
- Utile per audit e reporting
DeletionSyncService - Nuovo Servizio
Servizio dedicato alla sincronizzazione delle cancellazioni dalla sorgente alla destinazione.
SyncDeletionsAsync
Task<DeletionSyncResult> SyncDeletionsAsync(
List<string> currentSourceKeyValues,
string destinationEntity,
string restCredentialName,
IRestServiceClient restClient,
DeletionSyncOptions options)
Processo Completo:
1. Marca Cancellazioni
↓
2. Recupera Cancellazioni Pending
↓
3. Per ogni cancellazione:
├─ Delete: Elimina fisicamente il record
├─ Deactivate: Imposta IsActive/Active = false
└─ Mark: Imposta campo personalizzato
↓
4. Marca come sincronizzate
↓
5. Ritorna DeletionSyncResult
Modalità di Cancellazione
1. Delete (Eliminazione Fisica)
DeletionAction.Delete
- Elimina completamente il record dalla destinazione
- Utilizza
IRestServiceClient.DeleteEntityAsync() - Irreversibile - il record viene rimosso permanentemente
2. Deactivate (Disattivazione)
DeletionAction.Deactivate
- Imposta campi
IsActiveoActiveafalse - Il record rimane nel database ma è marcato come inattivo
- Reversibile - può essere riattivato in futuro
3. Mark (Marcatura Personalizzata)
DeletionAction.Mark
options.MarkField = "IsDeleted"
options.MarkValue = "true"
- Imposta un campo personalizzato con un valore specifico
- Massima flessibilità - supporta qualsiasi logica di business
- Es:
Status = "Deleted",DeletedFlag = true, ecc.
3. Integrazione nei Flussi di Trasferimento
StartDataTransferOriginal (Trasferimento Standard)
Logica Aggiunta dopo Step 3 (Processo Record):
// 3.5 Sincronizza le cancellazioni (se abilitato)
if (useRecordAssociations && !string.IsNullOrEmpty(sourceKeyField))
{
// Estrai valori chiave dalla sorgente
var sourceKeyValues = records
.Select(r => r[sourceKeyField]?.ToString())
.Where(k => !string.IsNullOrEmpty(k))
.Distinct()
.ToList();
// Sincronizza cancellazioni
var deletionResult = await DeletionSyncService.SyncDeletionsAsync(
sourceKeyValues,
selectedRestEntity.Name,
selectedRestCredential,
currentRestClient,
new DeletionSyncOptions { Action = DeletionAction.Delete });
deletedCount = deletionResult.DeletedRecordsSynced;
// Aggiungi ai risultati del trasferimento
if (deletedCount > 0) { /* ... */ }
}
StartDataTransferWithComposite (Trasferimento Salesforce Composite)
Logica Aggiunta dopo Step 6 (Associazioni Parallele):
// 6.5 Sincronizza le cancellazioni (se abilitato)
// Stessa logica del metodo standard, adattata per Salesforce
4. Migrazioni Database
Migration 1: AddDeletionTrackingToKeyAssociations
// Aggiunge campi tracking cancellazioni a KeyAssociations
- IsSourceDeleted (bool, default: false)
- DeletedAt (DateTime?, nullable)
- DeletionSynced (bool, default: false)
- DeletionSyncedAt (DateTime?, nullable)
Migration 2: AddDeletionSyncToProfiles
// Aggiunge configurazione cancellazioni a DataCouplerProfiles
- SyncDeletions (bool, default: false)
- DeletionAction (string, default: "delete")
- DeletionMarkField (string, nullable)
- DeletionMarkValue (string, nullable)
5. Interfaccia Utente Aggiornata
Risultati Trasferimento
Header Card - Contatori Aggiornati:
<div class="col-2">
<small class="text-secondary">
<i class="fas fa-trash"></i>
Cancellati: @transferResults.Count(r => r.Status == "deleted")
</small>
</div>
Visualizzazione Stato Cancellato:
- Badge:
bg-secondarycon iconafa-trash - Testo: "Cancellato"
- Row Class:
table-secondary
Messaggi di Completamento
Messaggio di Successo:
Trasferimento completato con successo!
X record inseriti, Y record aggiornati, Z record cancellati.
Messaggio con Errori:
Trasferimento completato con errori.
Inserimenti: X, Aggiornamenti: Y, Cancellazioni: Z, Errori: W
🔄 Flusso di Lavoro Completo
Scenario: Sincronizzazione con Cancellazioni
┌─────────────────────────────────────────────────────────────┐
│ SORGENTE DATI │
│ Records: [A, B, C, D] → [A, B, D] (C cancellato) │
└─────────────────┬───────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ DATA-COUPLER - Trasferimento │
│ │
│ 1. Legge dati sorgente: [A, B, D] │
│ 2. Estrae chiavi: ["keyA", "keyB", "keyD"] │
│ 3. Trasferisce record A, B, D → Destinazione │
│ │
│ 4. SINCRONIZZAZIONE CANCELLAZIONI: │
│ ├─ Recupera associazioni esistenti: │
│ │ [keyA → ID1, keyB → ID2, keyC → ID3, keyD → ID4] │
│ │ │
│ ├─ Confronta con chiavi attuali: │
│ │ Missing: ["keyC"] → Record C cancellato! │
│ │ │
│ ├─ Marca associazione keyC: │
│ │ IsSourceDeleted = true │
│ │ DeletedAt = 2025-10-27 14:30:00 │
│ │ │
│ └─ Esegue cancellazione nella destinazione: │
│ ├─ Delete: DELETE /api/Entity/ID3 │
│ ├─ Deactivate: PATCH /api/Entity/ID3 {IsActive:false}│
│ └─ Mark: PATCH /api/Entity/ID3 {IsDeleted:true} │
│ │
│ 5. Marca sincronizzazione: │
│ DeletionSynced = true │
│ DeletionSyncedAt = 2025-10-27 14:30:05 │
└─────────────────┬───────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ DESTINAZIONE │
│ Records Before: [ID1, ID2, ID3, ID4] │
│ Records After: [ID1, ID2, ID4] (ID3 cancellato/marcato) │
└─────────────────────────────────────────────────────────────┘
📊 Risultati e Statistiche
DeletionSyncResult
public class DeletionSyncResult
{
public bool IsSuccess { get; set; }
public string Message { get; set; }
public int DeletedRecordsDetected { get; set; } // Quanti rilevati
public int DeletedRecordsSynced { get; set; } // Quanti sincronizzati
public int SyncErrors { get; set; } // Errori durante sync
public List<string> Errors { get; set; } // Dettagli errori
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration { get; set; }
}
Logging Dettagliato
Livello Info:
Verifica sincronizzazione cancellazioni...
Trovati 120 valori chiave nella sorgente
Rilevati 5 record cancellati dalla sorgente
Sincronizzazione cancellazioni: 5 rilevati, 5 sincronizzati, 0 errori
Livello Warning:
Marcata come cancellata: KeyValue=C00015, DestinationId=a1b2c3d4
Errore nella sincronizzazione della cancellazione per KeyValue: C00015
Livello Error:
Errore durante la sincronizzazione delle cancellazioni: Connection timeout
🔧 Dependency Injection
Registrazione in Program.cs
// Register Deletion Sync Service
builder.Services.AddScoped<Data_Coupler.Services.IDeletionSyncService,
Data_Coupler.Services.DeletionSyncService>();
Injection in DataCoupler.razor.cs
[Inject]
public IDeletionSyncService DeletionSyncService { get; set; } = default!;
🔐 Sicurezza e Best Practices
1. Validazione Pre-Cancellazione
- Verifica che il record esista prima di tentare la cancellazione
- Gestione graceful degli errori API
- Rollback delle marcature in caso di errore persistente
2. Audit Trail Completo
- Tutte le cancellazioni sono tracciate con timestamp
- Storico completo disponibile tramite
GetDeletedAssociationsAsync - Log dettagliati per compliance e debugging
3. Transazionalità
- Le marcature sono atomiche
- Gli errori in un record non bloccano gli altri
- Stato consistente tra database locale e destinazione
4. Performance
- Operazioni batch per confronto chiavi
- Processing parallelo non implementato (può essere aggiunto)
- Minimizzazione delle chiamate API
📈 Casi d'Uso
Caso 1: E-Commerce - Rimozione Prodotti
Scenario: Prodotti discontinuati nel sistema sorgente
Azione: DeletionAction.Mark
Config: MarkField="ProductStatus", MarkValue="Discontinued"
Risultato: Prodotti marcati come discontinuati ma ancora visibili per storico ordini
Caso 2: CRM - Clienti Inattivi
Scenario: Clienti rimossi dal database sorgente
Azione: DeletionAction.Deactivate
Config: Imposta IsActive=false
Risultato: Record cliente preservato per storico ma non più attivo
Caso 3: Inventario - Articoli Eliminati
Scenario: Articoli completamente rimossi dall'inventario
Azione: DeletionAction.Delete
Risultato: Eliminazione fisica del record dalla destinazione
⚠️ Limitazioni e Considerazioni
Limitazioni Attuali
- Solo REST APIs: La sincronizzazione funziona solo per destinazioni REST
- Chiave Obbligatoria: Richiede
useRecordAssociations = trueesourceKeyFieldconfigurato - Sincronizzazione Manuale: Non automatica, richiede esecuzione trasferimento
- Nessun Undo: Le cancellazioni fisiche (Delete) sono irreversibili
Considerazioni Performance
- Il confronto delle chiavi è O(n) dove n = numero di associazioni
- Ogni cancellazione richiede una chiamata API separata
- Per grandi volumi (>1000 cancellazioni) considerare batching
Gestione Errori
- Gli errori di cancellazione non bloccano il trasferimento principale
- Errori API sono loggati ma non causano rollback
- Retry logic non implementata (da aggiungere se necessario)
🚀 Evoluzioni Future
Funzionalità Proposte
-
Sincronizzazione Automatica Schedulata
- Background job per verificare periodicamente cancellazioni
- Configurabile per profilo (es: ogni ora, ogni giorno)
-
Soft Delete con Recovery
- Periodo di grazia prima dell'eliminazione fisica
- UI per recuperare cancellazioni recenti
-
Batch Deletion API
- Utilizzare Salesforce Composite per cancellazioni batch
- Ridurre chiamate API da N a ceil(N/200)
-
Conflict Resolution
- Gestione record modificati dopo marcatura cancellazione
- Opzioni per annullare o forzare la cancellazione
-
Dashboard Cancellazioni
- Visualizzazione centralizzata delle cancellazioni
- Statistiche e trend temporali
- Export per audit e compliance
-
Supporto Database Destinations
- Estendere sincronizzazione a destinazioni database
- Utilizzo di soft delete (UPDATE invece di DELETE)
📚 Riferimenti Codice
File Modificati
CredentialManager/
├── Models/
│ ├── KeyAssociation.cs (4 nuovi campi)
│ └── DataCouplerProfile.cs (4 nuovi campi)
├── Services/
│ ├── KeyAssociationService.cs (4 nuovi metodi)
│ └── IKeyAssociationService.cs (4 nuove signature)
└── Migrations/
├── 20251027000000_AddDeletionTrackingToKeyAssociations.cs
└── 20251027000001_AddDeletionSyncToProfiles.cs
DataConnection/
└── CredentialManagement/
├── Interfaces/
│ └── IDataConnectionCredentialService.cs (4 nuove signature)
└── Services/
└── DataConnectionCredentialService.cs (4 nuove implementazioni)
Data_Coupler/
├── Services/
│ └── DeletionSyncService.cs (NUOVO FILE)
├── Pages/
│ ├── DataCoupler.razor (UI aggiornata)
│ └── DataCoupler.razor.cs (logica integrata)
└── Program.cs (DI registration)
Linee di Codice Aggiunte
- Modelli: ~80 linee
- Servizi: ~400 linee
- Migrazioni: ~60 linee
- UI/Logica: ~250 linee
- TOTALE: ~790 linee di codice
✅ Testing e Validazione
Scenari di Test Consigliati
-
Test Rilevamento Base
- Trasferisci 10 record - Cancella 3 record dalla sorgente - Esegui nuovo trasferimento - Verifica: 3 cancellazioni rilevate e sincronizzate -
Test Modalità Cancellazione
- Test Delete: Verifica rimozione fisica - Test Deactivate: Verifica campo IsActive=false - Test Mark: Verifica campo personalizzato impostato -
Test Gestione Errori
- Record già cancellato nella destinazione - API non disponibile - Permessi insufficienti - Verifica: Errori loggati, processo continua -
Test Performance
- 1000 record con 100 cancellazioni - Misurare tempo di esecuzione - Verificare utilizzo memoria -
Test Associazioni
- Verifica campi IsSourceDeleted, DeletedAt - Verifica DeletionSynced, DeletionSyncedAt - Verifica storico completo
📝 Note di Rilascio
Versione 1.0 - 27 Ottobre 2025
Nuove Funzionalità:
- ✅ Sistema completo di sincronizzazione cancellazioni
- ✅ Tre modalità di cancellazione (Delete, Deactivate, Mark)
- ✅ Tracking completo delle cancellazioni nelle associazioni
- ✅ Integrazione trasparente nei flussi esistenti
- ✅ UI aggiornata con visualizzazione cancellazioni
Migrazioni Database:
- ✅
20251027000000_AddDeletionTrackingToKeyAssociations - ✅
20251027000001_AddDeletionSyncToProfiles
Breaking Changes:
- Nessuno - tutte le modifiche sono backward compatible
Deprecazioni:
- Nessuna
🤝 Contributori
- Sviluppo: Assistente AI (GitHub Copilot)
- Architettura: Basata su sistema esistente Data-Coupler
- Review: Da eseguire da team di sviluppo
📞 Supporto
Per domande o problemi relativi alla sincronizzazione delle cancellazioni:
- Documentazione: Questo file
- Log: Verifica log applicazione per dettagli errori
- Debug: Livello log "Information" per trace completo
Fine Documentazione - Deletion Sync Implementation v1.0