feat: Implementa gestione intelligente della chiave sorgente con rilevamento PK

- Aggiunge rilevamento automatico Primary Key per connessioni database
- Rimuove completamente il fallback automatico per lato sorgente
- Implementa selezione manuale obbligatoria per file e sorgenti non-DB
- Migliora UI con suggerimenti intelligenti e feedback visivo
- Aggiunge validazione multi-livello (UI, pre-transfer, runtime)
- Introduce metodo GetPrimaryKeyFieldAsync in IDatabaseManager
- Modifica GenerateSourceKey per richiedere sempre campo specifico
- Implementa controllo IsTransferButtonEnabled per validazione form

Breaking changes:
- La generazione automatica delle chiavi sorgente è stata rimossa
- Il campo chiave sorgente è ora obbligatorio quando si usa il sistema associazioni

Fixes: Risolve problema di discovery schema vuoto con selezione database
This commit is contained in:
2025-06-28 02:05:59 +02:00
parent 207d6fc845
commit 51c61eabf7
29 changed files with 2748 additions and 104 deletions
@@ -64,15 +64,27 @@ public class DatabaseInitializer : IDatabaseInitializer
{
try
{
// Prova a fare una query semplice per verificare che la tabella esista
// Verifica che la tabella principale Credentials esista
await _context.Credentials.CountAsync();
_logger.LogInformation("Verifica tabelle completata con successo");
}
catch (Exception ex)
{
_logger.LogWarning("Tabelle mancanti, ricreazione database...");
_logger.LogInformation("Tabella Credentials verificata con successo");
// Se le tabelle non esistono, le ricreiamo
// Verifica se la tabella RecordAssociations esiste, se non esiste la crea senza ricreare tutto il database
try
{
await _context.RecordAssociations.CountAsync();
_logger.LogInformation("Tabella RecordAssociations verificata con successo");
}
catch (Exception)
{
_logger.LogInformation("Tabella RecordAssociations non trovata, creazione tramite migrazione...");
await CreateRecordAssociationsTableAsync();
}
}
catch (Exception)
{
_logger.LogWarning("Tabella Credentials mancante, ricreazione database...");
// Solo se la tabella principale non esiste, ricreiamo tutto
await _context.Database.EnsureDeletedAsync();
await _context.Database.EnsureCreatedAsync();
await SeedInitialDataAsync();
@@ -142,7 +154,7 @@ public class DatabaseInitializer : IDatabaseInitializer
{
_logger.LogInformation("Verifica e applicazione migrazioni...");
// Verifica se la colonna RestServiceType esiste usando una query diretta
// Migrazione 1: Verifica se la colonna RestServiceType esiste
try
{
await _context.Database.ExecuteSqlRawAsync(
@@ -157,6 +169,62 @@ public class DatabaseInitializer : IDatabaseInitializer
"ALTER TABLE Credentials ADD COLUMN RestServiceType TEXT");
_logger.LogInformation("Colonna RestServiceType aggiunta con successo");
}
// Migrazione 2: Verifica se la tabella RecordAssociations esiste
try
{
await _context.Database.ExecuteSqlRawAsync(
"SELECT COUNT(*) FROM RecordAssociations LIMIT 1");
_logger.LogInformation("Tabella RecordAssociations già presente");
}
catch (Microsoft.Data.Sqlite.SqliteException)
{
// La tabella non esiste, la creiamo
_logger.LogInformation("Creazione tabella RecordAssociations...");
// Crea la tabella
await _context.Database.ExecuteSqlRawAsync(@"
CREATE TABLE RecordAssociations (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
SourceName TEXT NOT NULL,
SourceType TEXT NOT NULL,
SourceKey TEXT NOT NULL,
DestinationEntity TEXT NOT NULL,
DestinationId TEXT NOT NULL,
RestCredentialName TEXT NOT NULL,
CreatedAt TEXT NOT NULL DEFAULT (datetime('now')),
UpdatedAt TEXT,
IsActive INTEGER NOT NULL DEFAULT 1,
AdditionalInfo TEXT
)");
// Crea gli indici
await _context.Database.ExecuteSqlRawAsync(@"
CREATE UNIQUE INDEX IX_RecordAssociations_Unique
ON RecordAssociations (SourceName, SourceKey, DestinationEntity)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_SourceType
ON RecordAssociations (SourceType)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_DestinationEntity
ON RecordAssociations (DestinationEntity)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_RestCredentialName
ON RecordAssociations (RestCredentialName)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_IsActive
ON RecordAssociations (IsActive)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_CreatedAt
ON RecordAssociations (CreatedAt)");
_logger.LogInformation("Tabella RecordAssociations creata con successo");
}
}
catch (Exception ex)
{
@@ -164,4 +232,60 @@ public class DatabaseInitializer : IDatabaseInitializer
throw;
}
}
private async Task CreateRecordAssociationsTableAsync()
{
try
{
_logger.LogInformation("Creazione tabella RecordAssociations...");
// Crea la tabella
await _context.Database.ExecuteSqlRawAsync(@"
CREATE TABLE RecordAssociations (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
SourceName TEXT NOT NULL,
SourceType TEXT NOT NULL,
SourceKey TEXT NOT NULL,
DestinationEntity TEXT NOT NULL,
DestinationId TEXT NOT NULL,
RestCredentialName TEXT NOT NULL,
CreatedAt TEXT NOT NULL DEFAULT (datetime('now')),
UpdatedAt TEXT,
IsActive INTEGER NOT NULL DEFAULT 1,
AdditionalInfo TEXT
)");
// Crea gli indici
await _context.Database.ExecuteSqlRawAsync(@"
CREATE UNIQUE INDEX IX_RecordAssociations_Unique
ON RecordAssociations (SourceName, SourceKey, DestinationEntity)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_SourceType
ON RecordAssociations (SourceType)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_DestinationEntity
ON RecordAssociations (DestinationEntity)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_RestCredentialName
ON RecordAssociations (RestCredentialName)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_IsActive
ON RecordAssociations (IsActive)");
await _context.Database.ExecuteSqlRawAsync(@"
CREATE INDEX IX_RecordAssociations_CreatedAt
ON RecordAssociations (CreatedAt)");
_logger.LogInformation("Tabella RecordAssociations creata con successo");
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nella creazione della tabella RecordAssociations");
throw;
}
}
}