diff --git a/Src/A69WD/Data/DBTools.cs b/Src/A69WD/Data/DBTools.cs index e0b4cff..33d17db 100644 --- a/Src/A69WD/Data/DBTools.cs +++ b/Src/A69WD/Data/DBTools.cs @@ -867,7 +867,7 @@ namespace A69WD { /// /// Identificativo del racconto desiderato /// Ritorna il racconto estratto dal DB - public cRac GetRacById(long IDrac) { + public cRac GetRacById_Orig(long IDrac) { lock (objLock) { cRac rac = null; List tmp = null; @@ -1071,8 +1071,105 @@ namespace A69WD { } } + public cRac GetRacById(long IDrac) { + /* + * Il metodo più pulito e leggibile consiste nell'eseguire una query principale per + * i dati del racconto e poi delle query mirate per popolare le collezioni. + * + * Ecco come implementare la funzione in C# utilizzando Microsoft.Data.Sqlite. + * + * Spiegazione della logica: + * - LEFT JOIN: Ho usato i LEFT JOIN nella query principale così, anche se un racconto + * non ha ancora una trama o un voto assegnato, il record viene comunque recuperato + * correttamente senza errori. + * - Mapping Manuale: Poiché non stiamo usando un ORM pesante (come Entity Framework), + * mappiamo manualmente le colonne del reader alle proprietà dell'oggetto cRac. + * - Gestione Valori Nulli: Noterai il controllo reader["Trama"]?.ToString() ?? "" che + * evita eccezioni nel caso in cui certi campi opzionali siano vuoti nel database. + * - Helper GetList: Per evitare di riscrivere lo stesso codice 3 volte per Autori, + * Tags e Origini, ho creato una piccola funzione di supporto. + * + * Questo approccio è molto performante su SQLite e ti restituisce l'oggetto cRac + * esattamente come lo avevi immaginato, pronto per essere mostrato nella tua + * interfaccia utente. + * + */ + lock (objLock) { + cRac rac = null; + // 1. Query principale: Dati Racconto, Trama e Voto + string queryBase = @" + SELECT r.*, t.Trama, v.Voto as Voto + FROM Racconti r + LEFT JOIN Trame t ON r.IDrac = t.IDrac + LEFT JOIN Links_Rac_Vot lrv ON r.IDrac = lrv.IDrac + LEFT JOIN Voti v ON lrv.IDvot = v.IDvot + WHERE r.IDrac = @IDrac"; + using (SQLiteCommand cmd = new SQLiteCommand(queryBase, cn)) { + cmd.Parameters.AddWithValue("@IDrac", IDrac); + using (SQLiteDataReader reader = cmd.ExecuteReader()) { + if (reader.Read()) { + rac = new cRac { + IDrac = Convert.ToInt64(reader["IDrac"]), + Title = reader["Title"].ToString(), + SubTitle = reader["SubTitle"].ToString(), + Creato = DateTime.Parse(reader["Creato"] as string), + Updated = DateTime.Parse(reader["Aggiornato"].ToString()), + Trama = reader["Trama"]?.ToString() ?? "", + Voto = reader["Voto"]?.ToString() ?? "Non Letto" + }; + } + } + } + if (rac == null) return null; // Racconto non trovato + // 2. Recupero Autori + rac.Autori = GetList(cn, "SELECT a.Autore FROM Autori a JOIN Links_Rac_Aut l ON a.IDaut = l.IDaut WHERE l.IDrac = @IDrac", IDrac); + + // 3. Recupero Tags + rac.Tags = GetList(cn, "SELECT t.Tag FROM Tags t JOIN Links_Rac_Tag l ON t.IDtag = l.IDtag WHERE l.IDrac = @IDrac", IDrac); + + // 4. Recupero Origini + rac.Origini = GetList(cn, "SELECT o.Origine FROM Origini o JOIN Links_Rac_Ori l ON o.IDori = l.IDori WHERE l.IDrac = @IDrac", IDrac); + + // 5. Recupero Note (Key-Value) + string queryNotes = @" + SELECT n.NKey, n.NVal + FROM Notes n + JOIN Links_Rac_Not l ON n.IDnot = l.IDnot + WHERE l.IDrac = @IDrac"; + using (var cmd = new SQLiteCommand(queryNotes, cn)) { + cmd.Parameters.AddWithValue("@IDrac", IDrac); + using (var reader = cmd.ExecuteReader()) { + while (reader.Read()) { + cNota nt = new cNota(reader["NKey"].ToString(), reader["NVal"].ToString()); + rac.Notes.Add(nt); + } + } + } + + // // 6. Recupero Segnalini + // string querySng = @" + // SELECT s.Linea, s.Segnalino + // FROM Segnalini s + // JOIN Links_Rac_Sng l ON s.IDsng = l.IDsng + // WHERE l.IDrac = @IDrac"; + // using (var cmd = new SQLteCommand(querySng, cn) { + // cmd.Parameters.AddWithValue("@IDrac", IDrac); + // using (var reader = cmd.ExecuteReader()) { + // while (reader.Read()) { + // rac.Segnalini.Add(new SegnalinoInfo { + // Linea = Convert.ToInt32(reader["Linea"]), + // Descrizione = reader["Segnalino"].ToString() + // }); + // } + // } + // } + + return rac; + + }//lock + } /// /// Importa il racconto passato sul DB @@ -1728,6 +1825,19 @@ namespace A69WD { + // Helper per la lettura rapida di liste di stringhe + public static List GetList(SQLiteConnection conn, string sql, long IDrac) { + var list = new List(); + using (var cmd = new SQLiteCommand(sql, conn)) { + cmd.Parameters.AddWithValue("@IDrac", IDrac); + using (var reader = cmd.ExecuteReader()) { + while (reader.Read()) list.Add(reader.GetValue(0).ToString()); + } + } + return list; + } + + } // class DBTools diff --git a/Src/A69WD/Data/cRac.cs b/Src/A69WD/Data/cRac.cs index 3557c59..c4b0c9e 100644 --- a/Src/A69WD/Data/cRac.cs +++ b/Src/A69WD/Data/cRac.cs @@ -36,7 +36,7 @@ namespace A69WD.Data { /// Default: '' /// Mappa [SubTitle] /// - public string SubTitle { get; set; } = ""; + public string SubTitle { get; set; } = string.Empty; /// /// Data di creazione/pubblicazione del racconto o in mancanza di essa, data di inserimento del racconto in ATDB @@ -58,10 +58,10 @@ namespace A69WD.Data { /// /// Testo completo della trama del racconto - /// Default: null + /// Default: '' /// Mappa [Trama] /// - public string Trama { get; set; } = null; + public string Trama { get; set; } = string.Empty; #endregion @@ -83,21 +83,21 @@ namespace A69WD.Data { /// Default: null /// Mappa la relazione tramite [Links_Rac_Aut] con la tabella [Autori]. /// - public List Autori { get; set; } = null; + public List Autori { get; set; } = new List(); /// /// Elenco dei tag o proprietà associati (es. Genere, Mood). /// Default: null /// Mappa la relazione tramite [Links_Rac_Tag] con la tabella [Tags]. /// - public List Tags { get; set; } = null; + public List Tags { get; set; } = new List(); /// /// Elenco delle sorgenti o origini da cui proviene il racconto. /// Default: null /// Mappa la relazione tramite [Links_Rac_Ori] con la tabella [Origini]. /// - public List Origini { get; set; } = null; + public List Origini { get; set; } = new List(); /// /// Note informative strutturate come coppia Chiave-Valore (es. Link, Resume). @@ -108,7 +108,7 @@ namespace A69WD.Data { /// Mappa la relazione tramite [Links_Rac_Not] con la tabella [Notes]. /// //public Dictionary Note { get; set; } = new Dictionary(); - public List Notes { get; set; } = null; + public List Notes { get; set; } = new List(); #endregion diff --git a/Src/A69WD/UI/frmDownloader.cs b/Src/A69WD/UI/frmDownloader.cs index e3b966f..4eabc09 100644 --- a/Src/A69WD/UI/frmDownloader.cs +++ b/Src/A69WD/UI/frmDownloader.cs @@ -184,18 +184,44 @@ namespace A69WD { private Service_Importer serviceImporter = null; private void btnTest_Click(object sender, EventArgs e) { - int MaxRac = 60; - pbST.Maximum = MaxRac; - pbST.Minimum = 0; - pbST.Value = 0; - lblST.Text = "Inizio esportazione racconti"; - for (int i = 0; i < 61; i++) { - cRac rac = App.DB.GetRacById(i); - cRac.EsportaInHtml(rac, Cfg.Settings.PathDownloadWorking); - pbST.Value = i; - lblST.Text = $"Esportato racconto ID={rac.strIDrac}"; + // Test dell'esportazione in html + //int MaxRac = 60; + //pbST.Maximum = MaxRac; + //pbST.Minimum = 0; + //pbST.Value = 0; + //lblST.Text = "Inizio esportazione racconti"; + //for (int i = 0; i < 61; i++) { + // cRac rac = App.DB.GetRacById(i); + // cRac.EsportaInHtml(rac, Cfg.Settings.PathDownloadWorking); + // pbST.Value = i; + // lblST.Text = $"Esportato racconto ID={rac.strIDrac}"; + //} + //lblST.Text = $"Fine esportazione {MaxRac.ToString("000")} racconti"; + + + + // Test funzione di lettura dal DB + Logger.Information("-- Start test 100*50 letture originali --"); + DateTime start = DateTime.Now; + for (int j = 0; j < 100; j++) { + for (int i = 1; i <= 50; i++) { + cRac rac = App.DB.GetRacById_Orig(i); + if (rac.IDrac != i) Logger.Information($"Letto ID={i.ToString()}"); + } } - lblST.Text = $"Fine esportazione {MaxRac.ToString("000")} racconti"; + TimeSpan tp = start-DateTime.Now; + Logger.Information($" End test in {tp.ToString()}"); + Logger.Information("-- Start test 100*50 letture nuove --"); + start = DateTime.Now; + for (int j = 0; j < 100; j++) { + for (int i = 1; i <= 50; i++) { + cRac rac = App.DB.GetRacById(i); + if (rac.IDrac != i) Logger.Information($"Letto ID={i.ToString()}"); + } + } + tp = start - DateTime.Now; + Logger.Information($" End test in {tp.ToString()}"); + }