using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using DataConnection.EF.SchemaProviders;
using DataConnection.Interfaces;
namespace DataConnection.DB;
///
/// Database manager per connessioni OLE DB dirette (es. Visual FoxPro, Access, Jet)
/// Nota: i driver OLE DB come VFPOLEDB.1 sono 32-bit only — pubblicare con --runtime win-x86 se necessario
///
public class OleDbDatabaseManager : IDatabaseManager
{
private readonly string _connectionString;
private readonly OleDbSchemaProvider _schemaProvider;
public OleDbDatabaseManager(string connectionString)
{
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
throw new PlatformNotSupportedException("OLE DB è supportato solo su Windows.");
_connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
_schemaProvider = new OleDbSchemaProvider();
}
public async Task TestConnectionAsync()
{
try
{
using var connection = new OleDbConnection(_connectionString);
await Task.Run(() => connection.Open());
return true;
}
catch
{
return false;
}
}
public Task> GetAsync(
Expression>? filter = null,
Func, IOrderedQueryable>? orderBy = null,
string includeProperties = "",
int? skip = null,
int? take = null) where T : class
{
throw new NotSupportedException("GetAsync con espressioni LINQ non è supportato per OLE DB. Usare ExecuteRawQueryAsync.");
}
public Task GetByIdAsync(object id) where T : class
{
throw new NotSupportedException("GetByIdAsync non è supportato per OLE DB. Usare ExecuteRawQueryAsync con clausola WHERE.");
}
public Task> ExecuteQueryAsync(string sql, params object[] parameters) where T : class
{
throw new NotSupportedException("ExecuteQueryAsync non è supportato per OLE DB. Usare ExecuteRawQueryAsync.");
}
public async Task>> ExecuteRawQueryAsync(string sql, string databaseName = "", params object[] parameters)
{
var results = new List>();
using var connection = new OleDbConnection(_connectionString);
await Task.Run(() => connection.Open());
// OLE DB file-based (VFP, Access) non supporta ChangeDatabaseAsync — il database è nel Data Source
// Ignoriamo databaseName per questa tipologia di provider
using var command = new OleDbCommand(sql, connection);
if (parameters != null && parameters.Length > 0)
{
for (int i = 0; i < parameters.Length; i++)
{
command.Parameters.Add(new OleDbParameter($"@p{i}", parameters[i] ?? DBNull.Value));
}
}
using var reader = await Task.Run(() => command.ExecuteReader());
while (reader.Read())
{
var row = new Dictionary();
for (int i = 0; i < reader.FieldCount; i++)
{
var fieldName = reader.GetName(i);
var value = reader.IsDBNull(i) ? DBNull.Value : reader.GetValue(i);
row[fieldName] = value;
}
results.Add(row);
}
return results;
}
public async Task ExecuteCommandAsync(string sql, params object[] parameters)
{
using var connection = new OleDbConnection(_connectionString);
await Task.Run(() => connection.Open());
using var command = new OleDbCommand(sql, connection);
if (parameters != null && parameters.Length > 0)
{
for (int i = 0; i < parameters.Length; i++)
{
command.Parameters.Add(new OleDbParameter($"@p{i}", parameters[i] ?? DBNull.Value));
}
}
return await Task.Run(() => command.ExecuteNonQuery());
}
public async Task> GetAvailableDatabasesAsync()
{
var databases = await _schemaProvider.GetAvailableDatabasesAsync(_connectionString);
return databases.ToList();
}
public async Task ChangeDatabaseAsync(string databaseName)
{
// I provider OLE DB file-based (VFP, Access) non supportano il cambio di database a runtime
// Il Data Source nella connection string definisce il database
Console.WriteLine($"[OleDb] ChangeDatabaseAsync ignorato per provider file-based (database: {databaseName})");
await Task.CompletedTask;
}
public async Task>> GetDatabaseSchemaAsync()
{
return await _schemaProvider.GetDatabaseSchemaAsync(_connectionString);
}
public async Task> GetTableNamesAsync()
{
return await _schemaProvider.GetTableNamesAsync(_connectionString);
}
public async Task> GetTableSchemaAsync(string tableName)
{
return await _schemaProvider.GetTableSchemaAsync(_connectionString, tableName);
}
public async Task>> GetAllRecordsAsync(string tableName)
{
var query = $"SELECT * FROM {tableName}";
return await ExecuteRawQueryAsync(query);
}
public async Task GetPrimaryKeyFieldAsync(string tableName)
{
try
{
var schema = await GetTableSchemaAsync(tableName);
var pkColumn = schema.FirstOrDefault(c => c.IsPrimaryKey);
return pkColumn?.Name;
}
catch
{
return null;
}
}
public async Task>> ExecuteQueryAsync(string query, int? maxRows = null)
{
var results = new List>();
using var connection = new OleDbConnection(_connectionString);
await Task.Run(() => connection.Open());
var commandText = maxRows.HasValue ? WrapQueryWithLimit(query, maxRows.Value) : query;
using var command = new OleDbCommand(commandText, connection);
using var reader = await Task.Run(() => command.ExecuteReader());
while (reader.Read())
{
var row = new Dictionary();
for (int i = 0; i < reader.FieldCount; i++)
{
var fieldName = reader.GetName(i);
var value = reader.IsDBNull(i) ? null : reader.GetValue(i);
row[fieldName] = value;
}
results.Add(row);
}
return results;
}
public async Task ExecuteNonQueryAsync(string query)
{
using var connection = new OleDbConnection(_connectionString);
await Task.Run(() => connection.Open());
using var command = new OleDbCommand(query, connection);
return await Task.Run(() => command.ExecuteNonQuery());
}
public async Task