feat: Corregge la logica di rilevamento database specificato nella connection string
- Modifica IsDatabaseSpecifiedInConnectionString per verificare prima il campo DatabaseName della credenziale - Aggiunge logging dettagliato per debugging del processo di connessione database - Corregge il flusso di connessione per evitare il modale quando il database è già specificato - Migliora la gestione degli errori nel caricamento tabelle dal database specificato - Rimuove codice non raggiungibile nella logica di connessione database Il bug precedente mostrava sempre il modale di selezione database anche quando il database era specificato nel campo DatabaseName della credenziale, ora la verifica segue la logica corretta: 1. Controlla se DatabaseName è valorizzato nella credenziale 2. Solo se vuoto, verifica i parametri Database=/Initial Catalog= nella connection string
This commit is contained in:
@@ -142,7 +142,8 @@ public class EFCoreDatabaseManager : IDatabaseManager
|
||||
{
|
||||
return await _context.Database.ExecuteSqlRawAsync(sql, parameters);
|
||||
}
|
||||
public async Task<IDictionary<string, IEnumerable<DbColumnInfo>>> GetDatabaseSchemaAsync()
|
||||
|
||||
public async Task<IDictionary<string, IEnumerable<DbColumnInfo>>> GetDatabaseSchemaAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -166,7 +167,91 @@ public class EFCoreDatabaseManager : IDatabaseManager
|
||||
Console.WriteLine($"Errore nel recupero dello schema del database: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
} public async Task<IEnumerable<Dictionary<string, object>>> GetAllRecordsAsync(string tableName)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene la lista dei database disponibili sul server
|
||||
/// </summary>
|
||||
/// <returns>Lista dei nomi dei database disponibili</returns>
|
||||
public async Task<List<string>> GetAvailableDatabasesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Usa la factory per ottenere il provider appropriato in base al tipo di database
|
||||
var schemaProvider = DatabaseSchemaProviderFactory.CreateProvider(_options.DatabaseType);
|
||||
|
||||
// Usa il provider per ottenere la lista dei database
|
||||
var connectionString = _context.Database.GetConnectionString();
|
||||
if (connectionString == null)
|
||||
throw new InvalidOperationException("Connection string is null");
|
||||
|
||||
var result = await schemaProvider.GetAvailableDatabasesAsync(connectionString);
|
||||
|
||||
return result.ToList();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nel recupero della lista dei database: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene solo la lista dei nomi delle tabelle disponibili (senza dettagli delle colonne)
|
||||
/// </summary>
|
||||
/// <returns>Lista dei nomi delle tabelle</returns>
|
||||
public async Task<IEnumerable<string>> GetTableNamesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Usa la factory per ottenere il provider appropriato in base al tipo di database
|
||||
var schemaProvider = DatabaseSchemaProviderFactory.CreateProvider(_options.DatabaseType);
|
||||
|
||||
// Usa il provider per ottenere la lista delle tabelle
|
||||
var connectionString = _context.Database.GetConnectionString();
|
||||
if (connectionString == null)
|
||||
throw new InvalidOperationException("Connection string is null");
|
||||
|
||||
var result = await schemaProvider.GetTableNamesAsync(connectionString);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nel recupero della lista delle tabelle: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene i dettagli delle colonne per una specifica tabella
|
||||
/// </summary>
|
||||
/// <param name="tableName">Nome della tabella (con schema se necessario)</param>
|
||||
/// <returns>Lista delle informazioni sulle colonne</returns>
|
||||
public async Task<IEnumerable<DbColumnInfo>> GetTableSchemaAsync(string tableName)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Usa la factory per ottenere il provider appropriato in base al tipo di database
|
||||
var schemaProvider = DatabaseSchemaProviderFactory.CreateProvider(_options.DatabaseType);
|
||||
|
||||
// Usa il provider per ottenere lo schema della tabella
|
||||
var connectionString = _context.Database.GetConnectionString();
|
||||
if (connectionString == null)
|
||||
throw new InvalidOperationException("Connection string is null");
|
||||
|
||||
var result = await schemaProvider.GetTableSchemaAsync(connectionString, tableName);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nel recupero dello schema della tabella {tableName}: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Dictionary<string, object>>> GetAllRecordsAsync(string tableName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -226,47 +311,6 @@ public class EFCoreDatabaseManager : IDatabaseManager
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetAvailableDatabasesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var connectionString = _context.Database.GetConnectionString();
|
||||
if (connectionString == null)
|
||||
throw new InvalidOperationException("Connection string is null");
|
||||
|
||||
// Crea una connessione al server (senza specificare il database)
|
||||
var serverConnectionString = GetServerConnectionString(connectionString);
|
||||
|
||||
using var connection = CreateConnection(serverConnectionString);
|
||||
await connection.OpenAsync();
|
||||
|
||||
using var command = connection.CreateCommand();
|
||||
|
||||
// Query per ottenere i database disponibili (esclude quelli di sistema)
|
||||
command.CommandText = @"
|
||||
SELECT name
|
||||
FROM sys.databases
|
||||
WHERE state_desc = 'ONLINE'
|
||||
AND name NOT IN ('master', 'tempdb', 'model', 'msdb', 'distribution')
|
||||
ORDER BY name";
|
||||
|
||||
var databases = new List<string>();
|
||||
using var reader = await command.ExecuteReaderAsync();
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
databases.Add(reader.GetString(0));
|
||||
}
|
||||
|
||||
return databases;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nell'ottenere la lista dei database: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ChangeDatabaseAsync(string databaseName)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -21,13 +21,29 @@ public class SqlServerSchemaProvider : IDatabaseSchemaProvider
|
||||
{
|
||||
await connection.OpenAsync();
|
||||
|
||||
// Prima verifichiamo se ci sono tabelle utente con una query semplice
|
||||
// Verifica se la connection string specifica già un database
|
||||
var connectionBuilder = new SqlConnectionStringBuilder(connectionString);
|
||||
var currentDatabase = connectionBuilder.InitialCatalog;
|
||||
|
||||
if (string.IsNullOrEmpty(currentDatabase))
|
||||
{
|
||||
// Nessun database specificato - restituisce dizionario vuoto per indicare
|
||||
// che è necessaria la selezione del database
|
||||
Console.WriteLine("Nessun database specificato nella connection string. È richiesta la selezione del database.");
|
||||
return new Dictionary<string, IEnumerable<DbColumnInfo>>();
|
||||
}
|
||||
|
||||
Console.WriteLine($"Analizzando database: {currentDatabase}");
|
||||
|
||||
// Prima verifichiamo se ci sono tabelle utente nel database specificato
|
||||
string testSql = "SELECT COUNT(*) FROM sys.tables WHERE is_ms_shipped = 0";
|
||||
using (var testCommand = new SqlCommand(testSql, connection))
|
||||
{
|
||||
var scalarResult = await testCommand.ExecuteScalarAsync();
|
||||
var tableCount = scalarResult != null ? (int)scalarResult : 0;
|
||||
|
||||
Console.WriteLine($"Trovate {tableCount} tabelle utente nel database {currentDatabase}");
|
||||
|
||||
if (tableCount == 0)
|
||||
{
|
||||
return new Dictionary<string, IEnumerable<DbColumnInfo>>(); // Restituisce dizionario vuoto
|
||||
@@ -141,6 +157,236 @@ public class SqlServerSchemaProvider : IDatabaseSchemaProvider
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene la lista dei database disponibili sul server SQL Server
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<string>> GetAvailableDatabasesAsync(string connectionString)
|
||||
{
|
||||
var databases = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
// Crea una connection string per il server (rimuove il database specifico)
|
||||
var connectionBuilder = new SqlConnectionStringBuilder(connectionString);
|
||||
connectionBuilder.InitialCatalog = ""; // Rimuove il database specifico
|
||||
var serverConnectionString = connectionBuilder.ConnectionString;
|
||||
|
||||
using (var connection = new SqlConnection(serverConnectionString))
|
||||
{
|
||||
await connection.OpenAsync();
|
||||
|
||||
// Query per ottenere i database disponibili (esclude quelli di sistema)
|
||||
string sql = @"
|
||||
SELECT name
|
||||
FROM sys.databases
|
||||
WHERE state_desc = 'ONLINE'
|
||||
AND name NOT IN ('master', 'tempdb', 'model', 'msdb', 'distribution')
|
||||
AND HAS_DBACCESS(name) = 1
|
||||
ORDER BY name";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
using (var reader = await command.ExecuteReaderAsync())
|
||||
{
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
databases.Add(reader.GetString(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nel recupero della lista dei database: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
|
||||
return databases;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene solo la lista dei nomi delle tabelle disponibili (senza dettagli delle colonne)
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<string>> GetTableNamesAsync(string connectionString)
|
||||
{
|
||||
var tableNames = new List<string>();
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
await connection.OpenAsync();
|
||||
|
||||
// Verifica se la connection string specifica già un database
|
||||
var connectionBuilder = new SqlConnectionStringBuilder(connectionString);
|
||||
var currentDatabase = connectionBuilder.InitialCatalog;
|
||||
|
||||
if (string.IsNullOrEmpty(currentDatabase))
|
||||
{
|
||||
Console.WriteLine("Nessun database specificato nella connection string per ottenere i nomi delle tabelle.");
|
||||
return new List<string>();
|
||||
}
|
||||
|
||||
Console.WriteLine($"Recuperando nomi tabelle dal database: {currentDatabase}");
|
||||
|
||||
// Query semplice per ottenere solo i nomi delle tabelle
|
||||
string sql = @"
|
||||
SELECT SCHEMA_NAME(t.schema_id) + '.' + t.name AS TableName
|
||||
FROM sys.tables t
|
||||
WHERE t.is_ms_shipped = 0
|
||||
ORDER BY TableName";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
using (var reader = await command.ExecuteReaderAsync())
|
||||
{
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
tableNames.Add(reader.GetString(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nel recupero dei nomi delle tabelle: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
|
||||
return tableNames;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ottiene i dettagli delle colonne per una specifica tabella
|
||||
/// </summary>
|
||||
public async Task<IEnumerable<DbColumnInfo>> GetTableSchemaAsync(string connectionString, string tableName)
|
||||
{
|
||||
var columns = new List<DbColumnInfo>();
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
await connection.OpenAsync();
|
||||
|
||||
// Verifica se la connection string specifica già un database
|
||||
var connectionBuilder = new SqlConnectionStringBuilder(connectionString);
|
||||
var currentDatabase = connectionBuilder.InitialCatalog;
|
||||
|
||||
if (string.IsNullOrEmpty(currentDatabase))
|
||||
{
|
||||
Console.WriteLine("Nessun database specificato nella connection string per ottenere lo schema della tabella.");
|
||||
return new List<DbColumnInfo>();
|
||||
}
|
||||
|
||||
Console.WriteLine($"Recuperando schema della tabella {tableName} dal database: {currentDatabase}");
|
||||
|
||||
// Separa schema e nome tabella
|
||||
string schemaName = "dbo";
|
||||
string tableNameOnly = tableName;
|
||||
if (tableName.Contains('.'))
|
||||
{
|
||||
var parts = tableName.Split('.');
|
||||
schemaName = parts[0];
|
||||
tableNameOnly = parts[1];
|
||||
}
|
||||
|
||||
// Query per ottenere i dettagli delle colonne di una specifica tabella
|
||||
string sql = @"
|
||||
SELECT
|
||||
c.name AS ColumnName,
|
||||
tp.name AS DataType,
|
||||
c.max_length,
|
||||
c.precision,
|
||||
c.scale,
|
||||
c.is_nullable,
|
||||
CASE WHEN pk.column_id IS NOT NULL THEN 1 ELSE 0 END AS IsPrimaryKey,
|
||||
CASE WHEN fk.parent_column_id IS NOT NULL THEN 1 ELSE 0 END AS IsForeignKey,
|
||||
SCHEMA_NAME(ref_t.schema_id) + '.' + ref_t.name AS ReferencedTable,
|
||||
ref_c.name AS ReferencedColumn
|
||||
FROM
|
||||
sys.tables t
|
||||
INNER JOIN
|
||||
sys.columns c ON t.object_id = c.object_id
|
||||
INNER JOIN
|
||||
sys.types tp ON c.user_type_id = tp.user_type_id
|
||||
LEFT JOIN
|
||||
(SELECT
|
||||
ic.object_id,
|
||||
ic.column_id
|
||||
FROM
|
||||
sys.indexes i
|
||||
INNER JOIN
|
||||
sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id
|
||||
WHERE
|
||||
i.is_primary_key = 1) pk ON t.object_id = pk.object_id AND c.column_id = pk.column_id
|
||||
LEFT JOIN
|
||||
sys.foreign_key_columns fk ON t.object_id = fk.parent_object_id AND c.column_id = fk.parent_column_id
|
||||
LEFT JOIN
|
||||
sys.tables ref_t ON fk.referenced_object_id = ref_t.object_id
|
||||
LEFT JOIN
|
||||
sys.columns ref_c ON fk.referenced_object_id = ref_c.object_id AND fk.referenced_column_id = ref_c.column_id
|
||||
WHERE
|
||||
t.is_ms_shipped = 0
|
||||
AND SCHEMA_NAME(t.schema_id) = @schemaName
|
||||
AND t.name = @tableName
|
||||
ORDER BY
|
||||
c.column_id";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
// Aggiungi parametri per evitare SQL injection
|
||||
var schemaParam = command.CreateParameter();
|
||||
schemaParam.ParameterName = "@schemaName";
|
||||
schemaParam.Value = schemaName;
|
||||
command.Parameters.Add(schemaParam);
|
||||
|
||||
var tableParam = command.CreateParameter();
|
||||
tableParam.ParameterName = "@tableName";
|
||||
tableParam.Value = tableNameOnly;
|
||||
command.Parameters.Add(tableParam);
|
||||
|
||||
using (var reader = await command.ExecuteReaderAsync())
|
||||
{
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
// Formato del tipo di dati con precisione e scala per tipi numerici o lunghezza per tipi stringa
|
||||
string dataType = reader.GetString(1);
|
||||
int maxLength = reader.GetInt16(2);
|
||||
byte precision = reader.GetByte(3);
|
||||
byte scale = reader.GetByte(4);
|
||||
|
||||
// Formattazione tipo di dati per SQL Server
|
||||
string formattedDataType = FormatSqlServerDataType(dataType, maxLength, precision, scale);
|
||||
|
||||
var columnInfo = new DbColumnInfo
|
||||
{
|
||||
Name = reader.GetString(0),
|
||||
DataType = formattedDataType,
|
||||
IsNullable = reader.GetBoolean(5),
|
||||
IsPrimaryKey = reader.GetInt32(6) == 1,
|
||||
IsForeignKey = reader.GetInt32(7) == 1,
|
||||
ReferencedTable = reader.IsDBNull(8) ? null : reader.GetString(8),
|
||||
ReferencedColumn = reader.IsDBNull(9) ? null : reader.GetString(9)
|
||||
};
|
||||
|
||||
columns.Add(columnInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Errore nel recupero dello schema della tabella {tableName}: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
private static string FormatSqlServerDataType(string dataType, int maxLength, byte precision, byte scale)
|
||||
{
|
||||
string formattedDataType = dataType;
|
||||
|
||||
Reference in New Issue
Block a user