Allineamento dati con repository di origine

This commit is contained in:
2025-08-17 23:40:09 +02:00
parent 93f3d02f32
commit f767fe6e35
55 changed files with 48638 additions and 0 deletions

View File

@@ -0,0 +1,293 @@
using CsvHelper;
using CsvHelper.Configuration;
using CsvHelper.TypeConversion;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace HorseRacingPredictor.Manager
{
/// <summary>
/// Gestore generico per la lettura di file CSV
/// </summary>
public class FileReader
{
public class NullableDecimalConverter : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
return ConvertToDecimal(text);
}
}
public class NullableIntConverter : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
return ConvertToInt(text);
}
}
/// <summary>
/// Legge un file CSV e lo converte in un DataTable
/// </summary>
/// <param name="filePath">Percorso del file CSV</param>
/// <returns>DataTable contenente i dati del file CSV</returns>
public DataTable ReadCsvToDataTable(string filePath)
{
if (string.IsNullOrEmpty(filePath))
{
throw new ArgumentException("Il percorso del file non può essere vuoto.", nameof(filePath));
}
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"File non trovato: {filePath}");
}
var dataTable = new DataTable();
// Configurazione per CsvHelper
var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
MissingFieldFound = null, // Ignora campi mancanti
TrimOptions = TrimOptions.Trim, // Rimuove spazi iniziali e finali
PrepareHeaderForMatch = args => args.Header.Replace("#", "").Trim() // Rimuove # e spazi dai nomi delle colonne
};
using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader, config))
{
// Legge l'intestazione
csv.Read();
csv.ReadHeader();
// Crea le colonne della tabella dai nomi delle colonne del CSV
foreach (var header in csv.HeaderRecord)
{
string columnName = header.Replace("#", "").Trim();
dataTable.Columns.Add(columnName);
}
// Legge i dati riga per riga
while (csv.Read())
{
var row = dataTable.NewRow();
for (int i = 0; i < csv.HeaderRecord.Length; i++)
{
string columnName = csv.HeaderRecord[i].Replace("#", "").Trim();
string value = csv.GetField(i) ?? string.Empty;
row[columnName] = value;
}
dataTable.Rows.Add(row);
}
}
return dataTable;
}
/// <summary>
/// Ottiene una lista di tutti i file CSV in una cartella e nelle sue sottocartelle
/// </summary>
/// <param name="folderPath">Percorso della cartella da esplorare</param>
/// <returns>Lista di percorsi dei file CSV trovati</returns>
public List<string> GetCsvFiles(string folderPath)
{
if (string.IsNullOrEmpty(folderPath))
{
throw new ArgumentException("Il percorso della cartella non può essere vuoto.", nameof(folderPath));
}
if (!Directory.Exists(folderPath))
{
throw new DirectoryNotFoundException($"Directory non trovata: {folderPath}");
}
var csvFiles = Directory.GetFiles(folderPath, "*.csv", SearchOption.AllDirectories);
return new List<string>(csvFiles);
}
/// <summary>
/// Metodo helper per estrarre un valore stringa da una riga di DataTable
/// </summary>
public string GetStringValue(DataRow row, string columnName)
{
if (!row.Table.Columns.Contains(columnName) || row[columnName] == DBNull.Value)
{
return string.Empty;
}
return row[columnName].ToString();
}
/// <summary>
/// Metodo helper per estrarre un valore intero da una riga di DataTable
/// Gestisce valori nulli o non validi restituendo 0
/// </summary>
public int GetIntValue(DataRow row, string columnName)
{
if (!row.Table.Columns.Contains(columnName) || row[columnName] == DBNull.Value)
{
return 0;
}
if (int.TryParse(row[columnName].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out int result))
{
return result;
}
return 0;
}
/// <summary>
/// Metodo helper per estrarre un valore intero nullable da una riga di DataTable
/// Restituisce null per valori mancanti o non validi
/// </summary>
public int? GetNullableIntValue(DataRow row, string columnName)
{
if (!row.Table.Columns.Contains(columnName) || row[columnName] == DBNull.Value)
{
return null;
}
string stringValue = row[columnName].ToString();
if (string.IsNullOrWhiteSpace(stringValue))
{
return null;
}
if (int.TryParse(stringValue, NumberStyles.Any, CultureInfo.InvariantCulture, out int result))
{
return result;
}
return null;
}
/// <summary>
/// Metodo helper per estrarre un valore decimale da una riga di DataTable con controllo di precisione
/// Gestisce valori nulli o non validi restituendo 0
/// </summary>
public decimal GetDecimalValue(DataRow row, string columnName, int precision, int scale)
{
if (!row.Table.Columns.Contains(columnName) || row[columnName] == DBNull.Value)
{
return 0.0M;
}
if (decimal.TryParse(row[columnName].ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out decimal result))
{
// Arrotonda il valore per rispettare il limite di precisione e scala
decimal factor = (decimal)Math.Pow(10, scale);
result = Math.Round(result, scale);
// Verifica se il valore è entro i limiti di precisione
decimal maxValue = (decimal)Math.Pow(10, precision - scale) - (1 / factor);
if (Math.Abs(result) > maxValue)
{
Console.WriteLine($"Valore fuori range per {columnName}: {result}, limitato a {maxValue}");
result = result < 0 ? -maxValue : maxValue;
}
return result;
}
return 0.0M;
}
/// <summary>
/// Metodo helper per estrarre un valore decimale nullable da una riga di DataTable
/// Restituisce null per valori mancanti o non validi
/// </summary>
public decimal? GetNullableDecimalValue(DataRow row, string columnName, int precision, int scale)
{
if (!row.Table.Columns.Contains(columnName) || row[columnName] == DBNull.Value)
{
return null;
}
string stringValue = row[columnName].ToString();
if (string.IsNullOrWhiteSpace(stringValue))
{
return null;
}
if (decimal.TryParse(stringValue, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal result))
{
// Arrotonda il valore per rispettare il limite di precisione e scala
decimal factor = (decimal)Math.Pow(10, scale);
result = Math.Round(result, scale);
// Verifica se il valore è entro i limiti di precisione
decimal maxValue = (decimal)Math.Pow(10, precision - scale) - (1 / factor);
if (Math.Abs(result) > maxValue)
{
Console.WriteLine($"Valore fuori range per {columnName}: {result}, limitato a {maxValue}");
result = result < 0 ? -maxValue : maxValue;
}
return result;
}
return null;
}
/// <summary>
/// Converte un valore stringa in int con gestione dei valori nulli o non validi
/// </summary>
public static int ConvertToInt(string value)
{
if (string.IsNullOrWhiteSpace(value))
return 0;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out int result))
return result;
return 0;
}
/// <summary>
/// Converte un valore stringa in decimal con gestione dei valori nulli o non validi
/// </summary>
public static decimal ConvertToDecimal(string value)
{
if (string.IsNullOrWhiteSpace(value))
return 0m;
if (decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal result))
return result;
return 0m;
}
/// <summary>
/// Converte un valore stringa in int? con gestione dei valori nulli o non validi
/// </summary>
public static int? ConvertToNullableInt(string value)
{
if (string.IsNullOrWhiteSpace(value))
return null;
if (int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out int result))
return result;
return null;
}
/// <summary>
/// Converte un valore stringa in decimal? con gestione dei valori nulli o non validi
/// </summary>
public static decimal? ConvertToNullableDecimal(string value)
{
if (string.IsNullOrWhiteSpace(value))
return null;
if (decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal result))
return result;
return null;
}
}
}