feat: Implementato sistema di associazioni chiave per prevenire duplicati nel data coupling
BREAKING CHANGE: Rimosso completamente il vecchio sistema RecordAssociation Modifiche principali: - Sostituito RecordAssociation con KeyAssociation basato sui valori delle chiavi - Implementata logica robusta di UPDATE vs INSERT basata su associazioni esistenti - Aggiunta normalizzazione delle chiavi (.Trim()) per consistenza - Implementato fallback nella ricerca associazioni per maggiore affidabilità - Sostituita verifica pre-UPDATE con tentativo diretto più efficiente Componenti modificati: - Nuovo modello: KeyAssociation.cs con campi ottimizzati - Nuovo servizio: KeyAssociationService.cs con metodi completi - Aggiornato: DataCoupler.razor con logica migliorata di gestione associazioni - Aggiornato: CredentialDbContext per gestire solo KeyAssociations - Aggiornati: tutti i servizi di interfaccia per supportare il nuovo sistema - Creata: pagina KeyAssociations.razor per gestione associazioni - Aggiornato: NavMenu.razor con link alla gestione associazioni Miglioramenti tecnici: - Logica di UPDATE più robusta: tenta direttamente l'aggiornamento invece di verificare prima l'esistenza - Gestione errori migliorata con cleanup automatico delle associazioni non valide - Debug logging estensivo per troubleshooting - Fallback nella ricerca associazioni se parametri specifici falliscono - Normalizzazione valori chiave per prevenire problemi di whitespace Risultato: Il sistema ora previene correttamente i duplicati utilizzando le associazioni per decidere se fare INSERT (nuovo record) o UPDATE (record esistente) basandosi sui valori delle chiavi. Database: - Creata migrazione EF per rimuovere RecordAssociations e aggiungere KeyAssociations - Eliminati file e codice legacy non più necessari
This commit is contained in:
@@ -68,16 +68,16 @@ public class DatabaseInitializer : IDatabaseInitializer
|
||||
await _context.Credentials.CountAsync();
|
||||
_logger.LogInformation("Tabella Credentials verificata con successo");
|
||||
|
||||
// Verifica se la tabella RecordAssociations esiste, se non esiste la crea senza ricreare tutto il database
|
||||
// Verifica se la tabella KeyAssociations esiste, se non esiste la crea senza ricreare tutto il database
|
||||
try
|
||||
{
|
||||
await _context.RecordAssociations.CountAsync();
|
||||
_logger.LogInformation("Tabella RecordAssociations verificata con successo");
|
||||
await _context.KeyAssociations.CountAsync();
|
||||
_logger.LogInformation("Tabella KeyAssociations verificata con successo");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.LogInformation("Tabella RecordAssociations non trovata, creazione tramite migrazione...");
|
||||
await CreateRecordAssociationsTableAsync();
|
||||
_logger.LogInformation("Tabella KeyAssociations non trovata, creazione tramite migrazione...");
|
||||
await CreateKeyAssociationsTableAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
@@ -170,60 +170,78 @@ public class DatabaseInitializer : IDatabaseInitializer
|
||||
_logger.LogInformation("Colonna RestServiceType aggiunta con successo");
|
||||
}
|
||||
|
||||
// Migrazione 2: Verifica se la tabella RecordAssociations esiste
|
||||
// Migrazione 2: Elimina vecchia tabella RecordAssociations se esiste e crea KeyAssociations
|
||||
try
|
||||
{
|
||||
// Prova a eliminare la vecchia tabella se esiste
|
||||
await _context.Database.ExecuteSqlRawAsync("DROP TABLE IF EXISTS RecordAssociations");
|
||||
_logger.LogInformation("Vecchia tabella RecordAssociations eliminata");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Ignora errori se la tabella non esiste
|
||||
}
|
||||
|
||||
// Verifica se la tabella KeyAssociations esiste
|
||||
try
|
||||
{
|
||||
await _context.Database.ExecuteSqlRawAsync(
|
||||
"SELECT COUNT(*) FROM RecordAssociations LIMIT 1");
|
||||
_logger.LogInformation("Tabella RecordAssociations già presente");
|
||||
"SELECT COUNT(*) FROM KeyAssociations LIMIT 1");
|
||||
_logger.LogInformation("Tabella KeyAssociations già presente");
|
||||
}
|
||||
catch (Microsoft.Data.Sqlite.SqliteException)
|
||||
{
|
||||
// La tabella non esiste, la creiamo
|
||||
_logger.LogInformation("Creazione tabella RecordAssociations...");
|
||||
_logger.LogInformation("Creazione tabella KeyAssociations...");
|
||||
|
||||
// Crea la tabella
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE TABLE RecordAssociations (
|
||||
CREATE TABLE KeyAssociations (
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
SourceName TEXT NOT NULL,
|
||||
SourceType TEXT NOT NULL,
|
||||
SourceKey TEXT NOT NULL,
|
||||
KeyValue TEXT NOT NULL,
|
||||
SourceKeyField TEXT NOT NULL,
|
||||
DestinationKeyField TEXT NOT NULL,
|
||||
DestinationEntity TEXT NOT NULL,
|
||||
DestinationId TEXT NOT NULL,
|
||||
RestCredentialName TEXT NOT NULL,
|
||||
CreatedAt TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UpdatedAt TEXT,
|
||||
LastVerifiedAt TEXT,
|
||||
IsActive INTEGER NOT NULL DEFAULT 1,
|
||||
SourcesInfo TEXT,
|
||||
AdditionalInfo TEXT
|
||||
)");
|
||||
|
||||
// Crea gli indici
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE UNIQUE INDEX IX_RecordAssociations_Unique
|
||||
ON RecordAssociations (SourceName, SourceKey, DestinationEntity)");
|
||||
CREATE INDEX IX_KeyAssociations_KeyValue
|
||||
ON KeyAssociations (KeyValue)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_SourceType
|
||||
ON RecordAssociations (SourceType)");
|
||||
CREATE UNIQUE INDEX IX_KeyAssociations_Unique
|
||||
ON KeyAssociations (KeyValue, DestinationEntity, RestCredentialName)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_DestinationEntity
|
||||
ON RecordAssociations (DestinationEntity)");
|
||||
CREATE INDEX IX_KeyAssociations_DestinationEntity
|
||||
ON KeyAssociations (DestinationEntity)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_RestCredentialName
|
||||
ON RecordAssociations (RestCredentialName)");
|
||||
CREATE INDEX IX_KeyAssociations_RestCredentialName
|
||||
ON KeyAssociations (RestCredentialName)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_IsActive
|
||||
ON RecordAssociations (IsActive)");
|
||||
CREATE INDEX IX_KeyAssociations_IsActive
|
||||
ON KeyAssociations (IsActive)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_CreatedAt
|
||||
ON RecordAssociations (CreatedAt)");
|
||||
CREATE INDEX IX_KeyAssociations_CreatedAt
|
||||
ON KeyAssociations (CreatedAt)");
|
||||
|
||||
_logger.LogInformation("Tabella RecordAssociations creata con successo");
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_KeyAssociations_LastVerifiedAt
|
||||
ON KeyAssociations (LastVerifiedAt)");
|
||||
|
||||
_logger.LogInformation("Tabella KeyAssociations creata con successo");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -233,58 +251,67 @@ public class DatabaseInitializer : IDatabaseInitializer
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateRecordAssociationsTableAsync()
|
||||
private async Task CreateKeyAssociationsTableAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Creazione tabella RecordAssociations...");
|
||||
_logger.LogInformation("Creazione tabella KeyAssociations...");
|
||||
|
||||
// Crea la tabella
|
||||
// Elimina la vecchia tabella se esiste
|
||||
await _context.Database.ExecuteSqlRawAsync("DROP TABLE IF EXISTS RecordAssociations");
|
||||
|
||||
// Crea la nuova tabella
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE TABLE RecordAssociations (
|
||||
CREATE TABLE KeyAssociations (
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
SourceName TEXT NOT NULL,
|
||||
SourceType TEXT NOT NULL,
|
||||
SourceKey TEXT NOT NULL,
|
||||
KeyValue TEXT NOT NULL,
|
||||
SourceKeyField TEXT NOT NULL,
|
||||
DestinationKeyField TEXT NOT NULL,
|
||||
DestinationEntity TEXT NOT NULL,
|
||||
DestinationId TEXT NOT NULL,
|
||||
RestCredentialName TEXT NOT NULL,
|
||||
CreatedAt TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
UpdatedAt TEXT,
|
||||
LastVerifiedAt TEXT,
|
||||
IsActive INTEGER NOT NULL DEFAULT 1,
|
||||
SourcesInfo TEXT,
|
||||
AdditionalInfo TEXT
|
||||
)");
|
||||
|
||||
// Crea gli indici
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE UNIQUE INDEX IX_RecordAssociations_Unique
|
||||
ON RecordAssociations (SourceName, SourceKey, DestinationEntity)");
|
||||
CREATE INDEX IX_KeyAssociations_KeyValue
|
||||
ON KeyAssociations (KeyValue)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_SourceType
|
||||
ON RecordAssociations (SourceType)");
|
||||
CREATE UNIQUE INDEX IX_KeyAssociations_Unique
|
||||
ON KeyAssociations (KeyValue, DestinationEntity, RestCredentialName)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_DestinationEntity
|
||||
ON RecordAssociations (DestinationEntity)");
|
||||
CREATE INDEX IX_KeyAssociations_DestinationEntity
|
||||
ON KeyAssociations (DestinationEntity)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_RestCredentialName
|
||||
ON RecordAssociations (RestCredentialName)");
|
||||
CREATE INDEX IX_KeyAssociations_RestCredentialName
|
||||
ON KeyAssociations (RestCredentialName)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_IsActive
|
||||
ON RecordAssociations (IsActive)");
|
||||
CREATE INDEX IX_KeyAssociations_IsActive
|
||||
ON KeyAssociations (IsActive)");
|
||||
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_RecordAssociations_CreatedAt
|
||||
ON RecordAssociations (CreatedAt)");
|
||||
CREATE INDEX IX_KeyAssociations_CreatedAt
|
||||
ON KeyAssociations (CreatedAt)");
|
||||
|
||||
_logger.LogInformation("Tabella RecordAssociations creata con successo");
|
||||
await _context.Database.ExecuteSqlRawAsync(@"
|
||||
CREATE INDEX IX_KeyAssociations_LastVerifiedAt
|
||||
ON KeyAssociations (LastVerifiedAt)");
|
||||
|
||||
_logger.LogInformation("Tabella KeyAssociations creata con successo");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Errore nella creazione della tabella RecordAssociations");
|
||||
_logger.LogError(ex, "Errore nella creazione della tabella KeyAssociations");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user