Implementato il supporto per la scoperta e la visualizzazione dello schema del database, inclusa la creazione di provider specifici per SQL Server e l'integrazione con il servizio di connessione al database.
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Threading.Tasks;
|
||||
using DataConnection.Interfaces;
|
||||
using Microsoft.Data.SqlClient;
|
||||
|
||||
namespace DataConnection.EF.SchemaProviders;
|
||||
|
||||
/// <summary>
|
||||
/// Provider di schema per database SQL Server
|
||||
/// </summary>
|
||||
public class SqlServerSchemaProvider : IDatabaseSchemaProvider
|
||||
{
|
||||
public async Task<IDictionary<string, IEnumerable<DbColumnInfo>>> GetDatabaseSchemaAsync(string connectionString)
|
||||
{
|
||||
var result = new Dictionary<string, IEnumerable<DbColumnInfo>>();
|
||||
|
||||
try
|
||||
{
|
||||
using (var connection = new SqlConnection(connectionString))
|
||||
{
|
||||
await connection.OpenAsync();
|
||||
|
||||
// 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<DbColumnInfo> 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<DbColumnInfo>();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user