using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; using DataConnection.Interfaces; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.Data.SqlClient; namespace DataConnection.EF; /// /// Implementazione di IExistingDatabaseManager basata su Entity Framework Core /// public class EFCoreDatabaseManager : IDatabaseManager { private readonly DbManagerOptions _options; private ExistingDatabaseContext _context; public EFCoreDatabaseManager(DbManagerOptions options) { _options = options ?? throw new ArgumentNullException(nameof(options)); InitializeContext(); } private void InitializeContext() { var optionsBuilder = new DbContextOptionsBuilder(); _options.DbContextConfigurator(optionsBuilder); _context = new ExistingDatabaseContext( optionsBuilder.Options, _options.ModelConfigurator, _options.EnableAutoDiscovery, _options.EntityAssembly, _options.EntityNamespace, _options.NamingStrategy); } public async Task TestConnectionAsync() { try { return await _context.Database.CanConnectAsync(); } catch { return false; } } public async Task> GetAsync( Expression> filter = null, Func, IOrderedQueryable> orderBy = null, string includeProperties = "", int? skip = null, int? take = null) where T : class { IQueryable query = _context.Set(); if (filter != null) { query = query.Where(filter); } foreach (var includeProperty in includeProperties.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { query = query.Include(includeProperty); } if (orderBy != null) { query = orderBy(query); } if (skip.HasValue) { query = query.Skip(skip.Value); } if (take.HasValue) { query = query.Take(take.Value); } return await query.ToListAsync(); } public async Task GetByIdAsync(object id) where T : class { return await _context.Set().FindAsync(id); } public async Task> ExecuteQueryAsync(string sql, params object[] parameters) where T : class { return await _context.Set().FromSqlRaw(sql, parameters).ToListAsync(); } public async Task ExecuteCommandAsync(string sql, params object[] parameters) { return await _context.Database.ExecuteSqlRawAsync(sql, parameters); } public async Task>> GetDatabaseSchemaAsync() { try { Console.WriteLine($"[DEBUG] Iniziando GetDatabaseSchemaAsync - DatabaseType: {_options.DatabaseType}"); // Assicurarsi che il contesto sia connesso await _context.Database.OpenConnectionAsync(); Console.WriteLine($"[DEBUG] Connessione al database aperta. Connection string: {_context.Database.GetConnectionString()}"); // Usa la factory per ottenere il provider appropriato in base al tipo di database var schemaProvider = DatabaseSchemaProviderFactory.CreateProvider(_options.DatabaseType); Console.WriteLine($"[DEBUG] Schema provider creato: {schemaProvider.GetType().Name}"); // Usa il provider per ottenere lo schema var result = await schemaProvider.GetDatabaseSchemaAsync(_context.Database.GetConnectionString()); Console.WriteLine($"[DEBUG] Schema ottenuto. Numero tabelle: {result?.Count ?? 0}"); if (result != null && result.Count > 0) { foreach (var table in result.Take(3)) { Console.WriteLine($"[DEBUG] Tabella: {table.Key}, Colonne: {table.Value?.Count() ?? 0}"); } } return result; } catch (Exception ex) { Console.WriteLine($"Errore nel recupero dello schema del database: {ex.Message}"); Console.WriteLine($"[DEBUG] Stack trace: {ex.StackTrace}"); throw; } } public async Task>> GetAllRecordsAsync(string tableName) { try { var records = new List>(); // Usa la stessa connection string utilizzata per il discovery dello schema var connectionString = _context.Database.GetConnectionString(); Console.WriteLine($"[DEBUG] GetAllRecordsAsync - Using connection string: {connectionString?.Substring(0, Math.Min(50, connectionString?.Length ?? 0))}..."); // Determina il tipo di connessione in base al DatabaseType using var connection = CreateConnection(connectionString); await connection.OpenAsync(); using var command = connection.CreateCommand(); // Query SQL semplice per ottenere tutti i record - limitiamo a 1000 per sicurezza // Se il nome della tabella contiene già lo schema (es. "dbo.OCRD"), lo usiamo così com'è // Altrimenti aggiungiamo le parentesi quadre string tableReference; if (tableName.Contains('.')) { // Il nome contiene già lo schema, separiamo e mettiamo entrambi tra parentesi quadre var parts = tableName.Split('.'); tableReference = $"[{parts[0]}].[{parts[1]}]"; } else { // Solo il nome della tabella, usiamo le parentesi quadre tableReference = $"[{tableName}]"; } command.CommandText = $"SELECT TOP 1000 * FROM {tableReference}"; Console.WriteLine($"[DEBUG] GetAllRecordsAsync - Query: {command.CommandText}"); using var reader = await command.ExecuteReaderAsync(); while (await reader.ReadAsync()) { var record = new Dictionary(); for (int i = 0; i < reader.FieldCount; i++) { var columnName = reader.GetName(i); var value = reader.IsDBNull(i) ? null : reader.GetValue(i); record[columnName] = value; } records.Add(record); } Console.WriteLine($"[DEBUG] GetAllRecordsAsync - Tabella: {tableName}, Record ottenuti: {records.Count}"); return records; } catch (Exception ex) { Console.WriteLine($"Errore nell'ottenere i record dalla tabella {tableName}: {ex.Message}"); throw; } } /// /// Crea una connessione database appropriata in base al tipo di database /// private DbConnection CreateConnection(string connectionString) { switch (_options.DatabaseType) { case Enums.DatabaseType.SqlServer: return new SqlConnection(connectionString); // Aggiungi altri tipi di database quando necessario // case Enums.DatabaseType.MySQL: // return new MySqlConnection(connectionString); // case Enums.DatabaseType.PostgreSQL: // return new NpgsqlConnection(connectionString); default: throw new NotSupportedException($"Database type {_options.DatabaseType} is not supported for direct connections"); } } public void Dispose() { _context?.Dispose(); } }