From c6ce814e1c10dbe2d19b802645e4eb4fefec4b08 Mon Sep 17 00:00:00 2001 From: Robert McRackan Date: Tue, 10 May 2022 16:18:09 -0400 Subject: [PATCH] Set the stage for batch processing --- Source/ApplicationServices/LibraryCommands.cs | 33 ++++++++++++++----- Source/DataLayer/EfClasses/UserDefinedItem.cs | 8 +++-- .../ProcessorAutomationController.cs | 15 ++++++--- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/Source/ApplicationServices/LibraryCommands.cs b/Source/ApplicationServices/LibraryCommands.cs index 3ceab15b..027ae536 100644 --- a/Source/ApplicationServices/LibraryCommands.cs +++ b/Source/ApplicationServices/LibraryCommands.cs @@ -266,30 +266,47 @@ namespace ApplicationServices /// Occurs when , , or /// changed values are successfully persisted. /// - public static event EventHandler BookUserDefinedItemCommitted; + public static event EventHandler BookUserDefinedItemCommitted; #region Update book details - public static int UpdateUserDefinedItem(Book book) + public static int UpdateUserDefinedItem(params Book[] books) => UpdateUserDefinedItem(books.ToList()); + public static int UpdateUserDefinedItem(IEnumerable books) { try { + if (books is null || !books.Any()) + return 0; + using var context = DbContexts.GetContext(); // Attach() NoTracking entities before SaveChanges() - context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + foreach (var book in books) + context.Attach(book.UserDefinedItem).State = Microsoft.EntityFrameworkCore.EntityState.Modified; + var qtyChanges = context.SaveChanges(); - if (qtyChanges > 0) + if (qtyChanges == 0) + return 0; + + // semi-arbitrary. At some point it's more worth it to do a full re-index than to do one offs. + // I did not benchmark before choosing the number here + if (qtyChanges > 15) + SearchEngineCommands.FullReIndex(); + else { - SearchEngineCommands.UpdateLiberatedStatus(book); - SearchEngineCommands.UpdateBookTags(book); - BookUserDefinedItemCommitted?.Invoke(null, book.AudibleProductId); + foreach (var book in books) + { + SearchEngineCommands.UpdateLiberatedStatus(book); + SearchEngineCommands.UpdateBookTags(book); + } } + BookUserDefinedItemCommitted?.Invoke(null, null); + return qtyChanges; } catch (Exception ex) { - Log.Logger.Error(ex, $"Error updating {nameof(book.UserDefinedItem)}"); + Log.Logger.Error(ex, $"Error updating {nameof(Book.UserDefinedItem)}"); throw; } } diff --git a/Source/DataLayer/EfClasses/UserDefinedItem.cs b/Source/DataLayer/EfClasses/UserDefinedItem.cs index f5da2cf8..28267a31 100644 --- a/Source/DataLayer/EfClasses/UserDefinedItem.cs +++ b/Source/DataLayer/EfClasses/UserDefinedItem.cs @@ -141,9 +141,11 @@ namespace DataLayer get => _bookStatus; set { - if (_bookStatus != value) - { - _bookStatus = value; + // PartialDownload is a live/ephemeral status, not a persistent one. Do not store + var displayStatus = value == LiberatedStatus.PartialDownload ? LiberatedStatus.NotLiberated : value; + if (_bookStatus != displayStatus) + { + _bookStatus = displayStatus; OnItemChanged(nameof(BookStatus)); } } diff --git a/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs b/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs index dca83b84..2433ac39 100644 --- a/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs +++ b/Source/LibationWinForms/BookLiberation/ProcessorAutomationController.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using DataLayer; @@ -61,7 +63,7 @@ namespace LibationWinForms.BookLiberation await new BackupSingle(logMe, backupBook, libraryBook).RunBackupAsync(); } - public static async Task BackupAllBooksAsync() + public static async Task BackupAllBooksAsync(List libraryBooks = null) { Serilog.Log.Logger.Information("Begin " + nameof(BackupAllBooksAsync)); @@ -69,7 +71,7 @@ namespace LibationWinForms.BookLiberation var logMe = LogMe.RegisterForm(automatedBackupsForm); var backupBook = CreateBackupBook(logMe); - await new BackupLoop(logMe, backupBook, automatedBackupsForm).RunBackupAsync(); + await new BackupLoop(logMe, backupBook, automatedBackupsForm, libraryBooks).RunBackupAsync(); } public static async Task ConvertAllBooksAsync() @@ -307,13 +309,16 @@ An error occurred while trying to process this book. protected override MessageBoxDefaultButton SkipDialogDefaultButton => MessageBoxDefaultButton.Button1; protected override DialogResult SkipResult => DialogResult.Ignore; - public BackupLoop(LogMe logMe, Processable processable, AutomatedBackupsForm automatedBackupsForm) - : base(logMe, processable, automatedBackupsForm) { } + private List libraryBooks { get; } + + public BackupLoop(LogMe logMe, Processable processable, AutomatedBackupsForm automatedBackupsForm, List libraryBooks = null) + : base(logMe, processable, automatedBackupsForm) + => this.libraryBooks = libraryBooks ?? ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking(); protected override async Task RunAsync() { // support for 'skip this time only' requires state. iterators provide this state for free. therefore: use foreach/iterator here - foreach (var libraryBook in Processable.GetValidLibraryBooks(ApplicationServices.DbContexts.GetLibrary_Flat_NoTracking())) + foreach (var libraryBook in Processable.GetValidLibraryBooks(libraryBooks)) { var keepGoing = await ProcessOneAsync(libraryBook, validate: false); if (!keepGoing)