using System; using System.Collections.Generic; using System.Data; using System.Threading.Tasks; using DataConnection.Interfaces; using Microsoft.Data.SqlClient; namespace DataConnection.EF.SchemaProviders; /// /// Provider di schema per database SQL Server /// public class SqlServerSchemaProvider : IDatabaseSchemaProvider { public async Task>> GetDatabaseSchemaAsync(string connectionString) { var result = new Dictionary>(); try { Console.WriteLine($"[DEBUG] SqlServerSchemaProvider - Connection string: {connectionString?.Substring(0, Math.Min(50, connectionString?.Length ?? 0))}..."); using (var connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); Console.WriteLine($"[DEBUG] SqlServerSchemaProvider - Connessione aperta"); // Query per ottenere la struttura delle tabelle in SQL Server string sql = @" SELECT SCHEMA_NAME(t.schema_id) + '.' + t.name AS TableName, 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 ORDER BY TableName, c.column_id"; using (var command = new SqlCommand(sql, connection)) { command.CommandType = CommandType.Text; using (var reader = await command.ExecuteReaderAsync()) { string currentTable = null; List columns = null; while (await reader.ReadAsync()) { string tableName = reader.GetString(0); // Se stiamo passando a una nuova tabella, aggiungiamo la tabella precedente e creiamo una nuova lista if (currentTable != tableName) { if (currentTable != null && columns != null && columns.Count > 0) { result[currentTable] = columns; } currentTable = tableName; columns = new List(); } // Formato del tipo di dati con precisione e scala per tipi numerici o lunghezza per tipi stringa string dataType = reader.GetString(2); int maxLength = reader.GetInt16(3); byte precision = reader.GetByte(4); byte scale = reader.GetByte(5); // Formattazione tipo di dati per SQL Server string formattedDataType = FormatSqlServerDataType(dataType, maxLength, precision, scale); var columnInfo = new DbColumnInfo { Name = reader.GetString(1), DataType = formattedDataType, IsNullable = reader.GetBoolean(6), IsPrimaryKey = reader.GetInt32(7) == 1, IsForeignKey = reader.GetInt32(8) == 1, ReferencedTable = reader.IsDBNull(9) ? null : reader.GetString(9), ReferencedColumn = reader.IsDBNull(10) ? null : reader.GetString(10) }; columns?.Add(columnInfo); } // Aggiungiamo l'ultima tabella if (currentTable != null && columns != null && columns.Count > 0) { result[currentTable] = columns; } Console.WriteLine($"[DEBUG] SqlServerSchemaProvider - Query completata. Trovate {result.Count} tabelle"); foreach (var table in result.Take(3)) { Console.WriteLine($"[DEBUG] SqlServerSchemaProvider - Tabella: {table.Key}, Colonne: {table.Value?.Count() ?? 0}"); } } } } } catch (Exception ex) { Console.WriteLine($"Errore nel recupero dello schema del database SQL Server: {ex.Message}"); throw; } return result; } private static string FormatSqlServerDataType(string dataType, int maxLength, byte precision, byte scale) { string formattedDataType = dataType; if (dataType == "nvarchar" || dataType == "varchar" || dataType == "char" || dataType == "nchar") { if (maxLength == -1) formattedDataType += "(MAX)"; else if (dataType.StartsWith("n")) // tipi Unicode - la lunghezza รจ in byte, dobbiamo dividerla per 2 formattedDataType += $"({maxLength / 2})"; else formattedDataType += $"({maxLength})"; } else if (dataType == "decimal" || dataType == "numeric") { formattedDataType += $"({precision},{scale})"; } return formattedDataType; } }