using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using CredentialManager.Data;
namespace CredentialManager.Services;
///
/// Interfaccia per l'inizializzazione del database
///
public interface IDatabaseInitializer
{
Task InitializeAsync();
Task DatabaseExistsAsync();
}
///
/// Servizio per l'inizializzazione del database SQLite
///
public class DatabaseInitializer : IDatabaseInitializer
{
private readonly CredentialDbContext _context;
private readonly ILogger _logger;
public DatabaseInitializer(CredentialDbContext context, ILogger logger)
{
_context = context;
_logger = logger;
} public async Task InitializeAsync()
{
try
{
_logger.LogInformation("Inizializzazione database in corso...");
// Per SQLite con EnsureCreatedAsync è più semplice e sicuro
// Crea il database e le tabelle se non esistono
var created = await _context.Database.EnsureCreatedAsync();
if (created)
{
_logger.LogInformation("Database creato con successo");
// Aggiungi dati di esempio se necessario
await SeedInitialDataAsync();
}
else
{
_logger.LogInformation("Database esistente trovato");
// Verifica che le tabelle esistano
await VerifyTablesAsync();
// Applica migrazioni se necessario
await ApplyMigrationsAsync();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore durante l'inizializzazione del database");
throw;
}
}
private async Task VerifyTablesAsync()
{
try
{
// Verifica che la tabella principale Credentials esista
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
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();
_logger.LogInformation("Database ricreato con successo");
}
}
public async Task DatabaseExistsAsync()
{
try
{
return await _context.Database.CanConnectAsync();
}
catch
{
return false;
}
}
private async Task SeedInitialDataAsync()
{
try
{
// Verifica se ci sono già dati
if (await _context.Credentials.AnyAsync())
{
_logger.LogInformation("Dati esistenti trovati. Seeding saltato.");
return;
}
_logger.LogInformation("Aggiunta dati di esempio...");
// Qui puoi aggiungere dati di esempio se necessario
// Ad esempio:
/*
var sampleCredentials = new List
{
new CredentialEntity
{
Name = "Esempio Database",
Type = "Database",
Host = "localhost",
Port = 1433,
DatabaseName = "TestDB",
Username = "testuser",
CreatedAt = DateTime.UtcNow,
CreatedBy = "System",
IsActive = true
}
};
_context.Credentials.AddRange(sampleCredentials);
await _context.SaveChangesAsync();
*/
_logger.LogInformation("Dati di esempio aggiunti con successo");
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore durante il seeding dei dati iniziali");
throw;
}
} private async Task ApplyMigrationsAsync()
{
try
{
_logger.LogInformation("Verifica e applicazione migrazioni...");
// Migrazione 1: Verifica se la colonna RestServiceType esiste
try
{
await _context.Database.ExecuteSqlRawAsync(
"SELECT RestServiceType FROM Credentials LIMIT 1");
_logger.LogInformation("Colonna RestServiceType già presente");
}
catch (Microsoft.Data.Sqlite.SqliteException)
{
// La colonna non esiste, la aggiungiamo
_logger.LogInformation("Aggiunta colonna RestServiceType...");
await _context.Database.ExecuteSqlRawAsync(
"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)
{
_logger.LogError(ex, "Errore nell'applicazione delle migrazioni");
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;
}
}
}