From 14e14ba9bd28892286516616e43c598e6f9fa870 Mon Sep 17 00:00:00 2001 From: Robert McRackan Date: Thu, 23 Sep 2021 14:33:04 -0400 Subject: [PATCH] batch book status updates bug fixes, esp. threading --- AppScaffolding/AppScaffolding.csproj | 2 +- DataLayer/EfClasses/UserDefinedItem.cs | 43 +++++++++++++++++++++++--- LibationSearchEngine/SearchEngine.cs | 2 +- LibationWinForms/Form1.cs | 2 ++ LibationWinForms/GridEntry.cs | 9 +++--- LibationWinForms/ProductsGrid.cs | 16 +++++++--- LibationWinForms/Program.cs | 9 ++++-- 7 files changed, 64 insertions(+), 19 deletions(-) diff --git a/AppScaffolding/AppScaffolding.csproj b/AppScaffolding/AppScaffolding.csproj index a0c9d5bc..1382447b 100644 --- a/AppScaffolding/AppScaffolding.csproj +++ b/AppScaffolding/AppScaffolding.csproj @@ -3,7 +3,7 @@ net5.0 - 6.0.5.1 + 6.0.6.1 diff --git a/DataLayer/EfClasses/UserDefinedItem.cs b/DataLayer/EfClasses/UserDefinedItem.cs index 1686d3a1..52deb335 100644 --- a/DataLayer/EfClasses/UserDefinedItem.cs +++ b/DataLayer/EfClasses/UserDefinedItem.cs @@ -106,6 +106,11 @@ namespace DataLayer #endregion #region LiberatedStatuses + /// + /// Occurs when , , or values change. + /// This signals the change of the in-memory value; it does not ensure that the new value has been persisted. + /// + public static event EventHandler ItemChanged; private LiberatedStatus _bookStatus; private LiberatedStatus? _pdfStatus; @@ -132,13 +137,41 @@ namespace DataLayer ItemChanged?.Invoke(this, nameof(PdfStatus)); } } + } + #endregion + + #region batch changes + public static event EventHandler Batch_ItemChanged; + public void BatchMode_UpdateBookStatus(LiberatedStatus value) + { + if (_bookStatus != value) + { + _bookStatus = value; + batchFlag = true; + } + } + + // don't overwrite current with null. Therefore input is "LiberatedStatus" not "LiberatedStatus?" + public void BatchMode_UpdatePdfStatus(LiberatedStatus value) + { + if (_pdfStatus != value) + { + _pdfStatus = value; + batchFlag = true; + } + } + + private static bool batchFlag = false; + + public static void BatchMode_Finalize() + { + if (batchFlag) + Batch_ItemChanged?.Invoke(null, null); + + batchFlag = false; } #endregion - /// - /// Occurs when , , or values change. - /// This signals the change of the in-memory value; it does not ensure that the new value has been persisted. - /// - public static event EventHandler ItemChanged; + public override string ToString() => $"{Book} {Rating} {Tags}"; } } diff --git a/LibationSearchEngine/SearchEngine.cs b/LibationSearchEngine/SearchEngine.cs index 01fdde9b..dd12ae45 100644 --- a/LibationSearchEngine/SearchEngine.cs +++ b/LibationSearchEngine/SearchEngine.cs @@ -315,7 +315,7 @@ namespace LibationSearchEngine var docs = searcher.Search(query, 1); var scoreDoc = docs.ScoreDocs.SingleOrDefault(); if (scoreDoc == null) - throw new Exception("document not found"); + return; var document = searcher.Doc(scoreDoc.Doc); diff --git a/LibationWinForms/Form1.cs b/LibationWinForms/Form1.cs index 38922123..b02257bb 100644 --- a/LibationWinForms/Form1.cs +++ b/LibationWinForms/Form1.cs @@ -34,6 +34,8 @@ namespace LibationWinForms this.FormClosing += (_, _) => this.SaveSizeAndLocation(Configuration.Instance); LibraryCommands.LibrarySizeChanged += reloadGridAndUpdateBottomNumbers; LibraryCommands.BookUserDefinedItemCommitted += setBackupCounts; + // used by async migrations to update ui when complete + DataLayer.UserDefinedItem.Batch_ItemChanged += reloadGridAndUpdateBottomNumbers; var format = System.Drawing.Imaging.ImageFormat.Jpeg; PictureStorage.SetDefaultImage(PictureSize._80x80, Properties.Resources.default_cover_80x80.ToBytes(format)); diff --git a/LibationWinForms/GridEntry.cs b/LibationWinForms/GridEntry.cs index 10f6e11a..5396cac2 100644 --- a/LibationWinForms/GridEntry.cs +++ b/LibationWinForms/GridEntry.cs @@ -27,17 +27,16 @@ namespace LibationWinForms #endregion + public event EventHandler Committed; + private Book Book => LibraryBook.Book; private Image _cover; - private Action Refilter { get; } - public GridEntry(LibraryBook libraryBook, Action refilterOnChanged = null) + public GridEntry(LibraryBook libraryBook) { LibraryBook = libraryBook; - Refilter = refilterOnChanged; _memberValues = CreateMemberValueDictionary(); - //Get cover art. If it's default, subscribe to PictureCached { (bool isDefault, byte[] picture) = FileManager.PictureStorage.GetPicture(new FileManager.PictureDefinition(Book.PictureId, FileManager.PictureSize._80x80)); @@ -142,7 +141,7 @@ namespace LibationWinForms Book.UserDefinedItem.BookStatus = displayStatus; - Refilter?.Invoke(); + Committed?.Invoke(this, null); } #endregion diff --git a/LibationWinForms/ProductsGrid.cs b/LibationWinForms/ProductsGrid.cs index 2f7a3196..9fcfe145 100644 --- a/LibationWinForms/ProductsGrid.cs +++ b/LibationWinForms/ProductsGrid.cs @@ -3,9 +3,9 @@ using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using ApplicationServices; -using DataLayer; using Dinah.Core; using Dinah.Core.DataBinding; +using Dinah.Core.Threading; using Dinah.Core.Windows.Forms; using LibationWinForms.Dialogs; @@ -130,7 +130,12 @@ namespace LibationWinForms } var orderedGridEntries = lib - .Select(lb => new GridEntry(lb, Filter)).ToList() + .Select(lb => + { + var entry = new GridEntry(lb); + entry.Committed += (_, __) => Filter(); + return entry; + }).ToList() // default load order .OrderByDescending(ge => (DateTime)ge.GetMemberValue(nameof(ge.PurchaseDate))) //// more advanced example: sort by author, then series, then title @@ -166,8 +171,11 @@ namespace LibationWinForms var bindingContext = BindingContext[_dataGridView.DataSource]; bindingContext.SuspendBinding(); { - for (var r = _dataGridView.RowCount - 1; r >= 0; r--) - _dataGridView.Rows[r].Visible = productIds.Contains(getGridEntry(r).AudibleProductId); + this.UIThreadSync(() => + { + for (var r = _dataGridView.RowCount - 1; r >= 0; r--) + _dataGridView.Rows[r].Visible = productIds.Contains(getGridEntry(r).AudibleProductId); + }); } //Causes repainting of the DataGridView diff --git a/LibationWinForms/Program.cs b/LibationWinForms/Program.cs index 80be122a..cde703b9 100644 --- a/LibationWinForms/Program.cs +++ b/LibationWinForms/Program.cs @@ -259,22 +259,25 @@ namespace LibationWinForms // assign these strings and enums/ints unconditionally. EFCore will only update if changed if (fileType == FileType.PDF) - book.UserDefinedItem.PdfStatus = LiberatedStatus.Liberated; + book.UserDefinedItem.BatchMode_UpdatePdfStatus(LiberatedStatus.Liberated); if (fileType == FileType.Audio) { var lhack = libhackFiles.FirstOrDefault(f => f.ContainsInsensitive(asin)); if (lhack is null) - book.UserDefinedItem.BookStatus = LiberatedStatus.Liberated; + book.UserDefinedItem.BatchMode_UpdateBookStatus(LiberatedStatus.Liberated); else { - book.UserDefinedItem.BookStatus = LiberatedStatus.Error; + book.UserDefinedItem.BatchMode_UpdateBookStatus(LiberatedStatus.Error); libhackFilesToDelete.Add(lhack); } } } + // in order: save to db, full reindex from db, refresh ui context.SaveChanges(); + ApplicationServices.SearchEngineCommands.FullReIndex(); + UserDefinedItem.BatchMode_Finalize(); // only do this after save changes foreach (var libhackFile in libhackFilesToDelete)