Correzione selezione database/schema nell'interfaccia Data Coupler

- Implementato discovery intelligente database vs schemi per ogni DBMS
- Aggiornate query SQL per mostrare solo database effettivi (non ruoli/schemi di sistema)
- Aggiunta UI modal per selezione database con riconnessione automatica
- Aggiunta UI modal fallback per selezione schema quando necessario
- Migliorate query discovery per SQL Server, PostgreSQL, MySQL e Oracle
- Implementata logica di riconnessione automatica al database selezionato
- Aggiornati testi e descrizioni dell'interfaccia per maggiore chiarezza
- Gestione prioritaria: database disponibili  fallback su schemi se necessario

Fixes: Menu selezione mostrava ruoli invece dei database reali
This commit is contained in:
2025-07-02 00:22:09 +02:00
parent 7e450a358b
commit 99da631aea
2 changed files with 327 additions and 17 deletions
+69 -2
View File
@@ -1155,7 +1155,7 @@
<div class="modal-body">
<p class="text-muted">
<i class="fas fa-info-circle"></i>
Il server non ha un database predefinito. Seleziona il database su cui eseguire le operazioni:
Sono stati trovati più database nel server. Seleziona il database da utilizzare:
</p>
@if (availableDatabases != null && availableDatabases.Any())
@@ -1169,6 +1169,10 @@
<option value="@db">@db</option>
}
</select>
<small class="form-text text-muted">
<i class="fas fa-lightbulb"></i>
Il database determina quali tabelle e viste saranno disponibili per il mapping.
</small>
</div>
}
else
@@ -1185,7 +1189,70 @@
</button>
<button type="button" class="btn btn-primary" @onclick="OnDatabaseSelected"
disabled="@string.IsNullOrEmpty(selectedDatabase)">
<i class="fas fa-check"></i> Conferma
<i class="fas fa-check"></i> Connetti al Database
</button>
</div>
</div>
</div>
</div>
}
<!-- Modal per la selezione dello schema -->
@if (showSchemaSelectionModal)
{
<div class="modal fade show d-block" style="background-color: rgba(0,0,0,0.5);">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-sitemap"></i> Seleziona Schema
</h5>
</div>
<div class="modal-body">
<p class="text-muted">
<i class="fas fa-info-circle"></i>
Sono stati trovati più schemi nel database. Seleziona lo schema da utilizzare:
</p>
@if (isLoadingSchemas)
{
<div class="text-center">
<div class="spinner-border spinner-border-sm me-2"></div>
Caricamento schemi...
</div>
}
else if (availableSchemas != null && availableSchemas.Any())
{
<div class="mb-3">
<label for="schemaSelect" class="form-label">Schemi disponibili:</label>
<select id="schemaSelect" class="form-select" @bind="selectedSchema">
<option value="">-- Seleziona uno schema --</option>
@foreach (var schema in availableSchemas)
{
<option value="@schema">@schema</option>
}
</select>
<small class="form-text text-muted">
<i class="fas fa-lightbulb"></i>
Lo schema determina quali tabelle e viste saranno disponibili per il mapping.
</small>
</div>
}
else
{
<div class="alert alert-warning">
<i class="fas fa-exclamation-triangle"></i>
Nessuno schema trovato o errore nel caricamento.
</div>
}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @onclick="CancelSchemaSelection">
<i class="fas fa-times"></i> Annulla
</button>
<button type="button" class="btn btn-primary" @onclick="OnSchemaSelected"
disabled="@string.IsNullOrEmpty(selectedSchema)">
<i class="fas fa-check"></i> Connetti con Schema
</button>
</div>
</div>
+258 -15
View File
@@ -53,10 +53,14 @@ public partial class DataCoupler
// Database selection
private List<string> availableDatabases = new();
private List<string> availableSchemas = new();
private string selectedDatabase = "";
private string selectedSchema = "";
private bool showDatabaseSelection = false;
private bool showDatabaseSelectionModal = false;
private bool showSchemaSelectionModal = false;
private bool isLoadingDatabases = false;
private bool isLoadingSchemas = false;
// Custom query functionality
private bool useCustomQuery = false;
@@ -1910,23 +1914,46 @@ public partial class DataCoupler
}
/// <summary>
/// Gestisce la situazione quando è richiesta la selezione di un database specifico
/// Gestisce la situazione quando è richiesta la selezione di un database o schema specifico
/// </summary>
private void HandleDatabaseSelectionRequired()
private async void HandleDatabaseSelectionRequired()
{
try
{
// Prova a ottenere la lista dei database disponibili
// TODO: Implementare se il DatabaseManager supporta GetAvailableDatabases
Logger.LogInformation("Database selection richiesta - implementazione da completare");
Logger.LogInformation("Schema discovery non ha restituito risultati. Tentativo di scoprire database disponibili...");
// Per ora, impostiamo un messaggio di errore informativo
databaseErrorMessage = "Schema discovery non ha restituito risultati. Potrebbe essere necessario specificare un database o schema specifico nella connessione.";
// Prima prova a ottenere la lista dei database disponibili
await LoadAvailableDatabases();
if (availableDatabases.Any())
{
// Se abbiamo database disponibili, mostra il modal per la selezione del database
Logger.LogInformation("Trovati {DatabaseCount} database disponibili", availableDatabases.Count);
showDatabaseSelectionModal = true;
StateHasChanged();
}
else
{
// Se non ci sono database, prova con gli schemi
await LoadAvailableSchemas();
if (availableSchemas.Any())
{
Logger.LogInformation("Trovati {SchemaCount} schemi disponibili", availableSchemas.Count);
showSchemaSelectionModal = true;
StateHasChanged();
}
else
{
// Nessuna opzione disponibile
databaseErrorMessage = "Impossibile rilevare database o schemi. Verificare le credenziali di connessione o il tipo di database.";
}
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Errore nella gestione della selezione database");
databaseErrorMessage = $"Errore nella selezione database: {ex.Message}";
Logger.LogError(ex, "Errore nella gestione della selezione database/schema");
databaseErrorMessage = $"Errore nella rilevazione di database/schemi: {ex.Message}";
}
}
@@ -2166,6 +2193,16 @@ public partial class DataCoupler
StateHasChanged();
}
/// <summary>
/// Annulla la selezione dello schema
/// </summary>
private void CancelSchemaSelection()
{
showSchemaSelectionModal = false;
selectedSchema = "";
StateHasChanged();
}
/// <summary>
/// Conferma la selezione del database
/// </summary>
@@ -2178,19 +2215,225 @@ public partial class DataCoupler
try
{
// TODO: Implementare la logica per connettersi al database selezionato
Logger.LogInformation("Database selezionato: {Database}", selectedDatabase);
Logger.LogInformation("Database selezionato: {Database}. Riconnessione al database...", selectedDatabase);
// Per ora, chiudi semplicemente il dialog
await Task.CompletedTask;
// Riconnetti al database utilizzando il database selezionato come schema
await ConnectToDatabaseWithSchema(selectedDatabase);
if (isDatabaseConnected)
{
Logger.LogInformation("Connessione completata con successo usando il database {Database}", selectedDatabase);
databaseErrorMessage = ""; // Pulisci eventuali errori precedenti
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Errore nella selezione del database");
databaseErrorMessage = $"Errore nella selezione database: {ex.Message}";
Logger.LogError(ex, "Errore nella connessione con il database selezionato");
databaseErrorMessage = $"Errore nella connessione con database {selectedDatabase}: {ex.Message}";
}
StateHasChanged();
}
/// <summary>
/// Conferma la selezione dello schema
/// </summary>
private async Task OnSchemaSelected()
{
if (string.IsNullOrEmpty(selectedSchema))
return;
showSchemaSelectionModal = false;
try
{
Logger.LogInformation("Schema selezionato: {Schema}. Riconnessione al database...", selectedSchema);
// Riconnetti al database utilizzando lo schema selezionato
await ConnectToDatabaseWithSchema(selectedSchema);
if (isDatabaseConnected)
{
Logger.LogInformation("Connessione completata con successo usando lo schema {Schema}", selectedSchema);
databaseErrorMessage = ""; // Pulisci eventuali errori precedenti
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Errore nella connessione con lo schema selezionato");
databaseErrorMessage = $"Errore nella connessione con schema {selectedSchema}: {ex.Message}";
}
StateHasChanged();
}
/// <summary>
/// Carica la lista degli schemi disponibili
/// </summary>
private async Task LoadAvailableSchemas()
{
if (currentDatabaseManager == null)
return;
isLoadingSchemas = true;
availableSchemas.Clear();
try
{
// Prova a ottenere tutti gli schemi/database disponibili
// Questo metodo potrebbe non essere disponibile su tutti i database manager
// In tal caso, proveremo con una query diretta
try
{
var allSchemas = await currentDatabaseManager.GetDatabaseSchemaAsync();
if (allSchemas != null)
{
// Estrai i nomi degli schemi dalle chiavi delle tabelle
var schemaNames = allSchemas.Keys
.Where(key => key.Contains('.'))
.Select(key => key.Split('.')[0])
.Distinct()
.OrderBy(schema => schema)
.ToList();
if (schemaNames.Any())
{
availableSchemas.AddRange(schemaNames);
Logger.LogInformation("Rilevati {SchemaCount} schemi dalle tabelle: {Schemas}",
schemaNames.Count, string.Join(", ", schemaNames));
return;
}
}
}
catch (Exception ex)
{
Logger.LogWarning(ex, "Impossibile ottenere schemi dal database manager, provo con query dirette");
}
// Se il metodo sopra non funziona, prova con query SQL specifiche per database
await TryLoadSchemasWithDirectQuery();
}
catch (Exception ex)
{
Logger.LogError(ex, "Errore nel caricamento degli schemi disponibili");
}
finally
{
isLoadingSchemas = false;
}
}
/// <summary>
/// Prova a caricare gli schemi con query SQL dirette
/// </summary>
private async Task TryLoadSchemasWithDirectQuery()
{
if (currentDatabaseManager == null)
return;
try
{
// Query diverse per ogni tipo di database - focalizzate sui database/cataloghi
var credential = databaseCredentials.FirstOrDefault(c => c.Name == selectedDatabaseCredential);
if (credential == null) return;
string? schemaQuery = credential.DatabaseType switch
{
DatabaseType.SqlServer => "SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') AND state = 0",
DatabaseType.PostgreSql => "SELECT datname FROM pg_database WHERE datistemplate = false AND datname NOT IN ('postgres', 'template0', 'template1')",
DatabaseType.MySql => "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys')",
DatabaseType.Oracle => "SELECT DISTINCT OWNER FROM ALL_TABLES WHERE OWNER NOT IN ('SYS', 'SYSTEM', 'DBSNMP', 'SYSMAN', 'OUTLN', 'ANONYMOUS', 'CTXSYS', 'EXFSYS', 'LBACSYS', 'MDSYS', 'MGMT_VIEW', 'OLAPSYS', 'OWBSYS', 'ORDDATA', 'ORDSYS', 'SI_INFORMTN_SCHEMA', 'WK_TEST', 'WKPROXY', 'WMSYS', 'XDB', 'APEX_040000', 'APEX_PUBLIC_USER', 'DIP', 'FLOWS_FILES', 'HR', 'IX', 'OE', 'PM', 'SCOTT', 'SH', 'BI')",
_ => null
};
if (!string.IsNullOrEmpty(schemaQuery))
{
Logger.LogInformation("Eseguendo query per database/schemi: {Query}", schemaQuery);
var results = await currentDatabaseManager.ExecuteRawQueryAsync(schemaQuery);
if (results != null && results.Any())
{
var schemas = results.Select(row =>
{
var firstValue = row.Values.FirstOrDefault();
return firstValue?.ToString() ?? "";
})
.Where(schema => !string.IsNullOrEmpty(schema))
.OrderBy(schema => schema)
.ToList();
if (schemas.Any())
{
availableSchemas.AddRange(schemas);
Logger.LogInformation("Caricati {SchemaCount} database/schemi via query diretta per {DatabaseType}: {Schemas}",
schemas.Count, credential.DatabaseType, string.Join(", ", schemas));
}
}
}
}
catch (Exception ex)
{
Logger.LogWarning(ex, "Errore nel caricamento database/schemi via query diretta");
}
}
/// <summary>
/// Carica la lista dei database disponibili
/// </summary>
private async Task LoadAvailableDatabases()
{
if (currentDatabaseManager == null)
return;
isLoadingDatabases = true;
availableDatabases.Clear();
try
{
var credential = databaseCredentials.FirstOrDefault(c => c.Name == selectedDatabaseCredential);
if (credential == null) return;
string? databaseQuery = credential.DatabaseType switch
{
DatabaseType.SqlServer => "SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb')",
DatabaseType.PostgreSql => "SELECT datname FROM pg_database WHERE datistemplate = false AND datname NOT IN ('postgres', 'template0', 'template1')",
DatabaseType.MySql => "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT IN ('information_schema', 'performance_schema', 'mysql', 'sys')",
_ => null
};
if (!string.IsNullOrEmpty(databaseQuery))
{
var results = await currentDatabaseManager.ExecuteRawQueryAsync(databaseQuery);
if (results != null && results.Any())
{
var databases = results.Select(row =>
{
var firstValue = row.Values.FirstOrDefault();
return firstValue?.ToString() ?? "";
})
.Where(db => !string.IsNullOrEmpty(db))
.OrderBy(db => db)
.ToList();
if (databases.Any())
{
availableDatabases.AddRange(databases);
Logger.LogInformation("Caricati {DatabaseCount} database per {DatabaseType}: {Databases}",
databases.Count, credential.DatabaseType, string.Join(", ", databases));
}
}
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Errore nel caricamento dei database disponibili");
}
finally
{
isLoadingDatabases = false;
}
}
}