From 5caa9c5687a149d46e77523cf774387210c9d739 Mon Sep 17 00:00:00 2001 From: Robert McRackan Date: Sat, 16 Apr 2022 16:36:49 -0400 Subject: [PATCH] Improved logging for import errors --- AppScaffolding/AppScaffolding.csproj | 2 +- ApplicationServices/LibraryCommands.cs | 51 ++++++++++++++++++-------- DataLayer/EfClasses/Category.cs | 2 +- DataLayer/EfClasses/Contributor.cs | 2 +- DtoImporterService/BookImporter.cs | 4 +- DtoImporterService/CategoryImporter.cs | 7 ++-- 6 files changed, 44 insertions(+), 24 deletions(-) diff --git a/AppScaffolding/AppScaffolding.csproj b/AppScaffolding/AppScaffolding.csproj index 5abc0c54..5c1c14ab 100644 --- a/AppScaffolding/AppScaffolding.csproj +++ b/AppScaffolding/AppScaffolding.csproj @@ -3,7 +3,7 @@ net6.0 - 6.7.7.1 + 6.7.8.1 diff --git a/ApplicationServices/LibraryCommands.cs b/ApplicationServices/LibraryCommands.cs index 963e4ce2..9609a25c 100644 --- a/ApplicationServices/LibraryCommands.cs +++ b/ApplicationServices/LibraryCommands.cs @@ -164,25 +164,46 @@ namespace ApplicationServices } private static async Task importIntoDbAsync(List importItems) + { + logTime("importIntoDbAsync -- pre db"); + using var context = DbContexts.GetContext(); + var libraryBookImporter = new LibraryBookImporter(context); + var newCount = await Task.Run(() => libraryBookImporter.Import(importItems)); + logTime("importIntoDbAsync -- post Import()"); + int qtyChanges = saveChanges(context); + logTime("importIntoDbAsync -- post SaveChanges"); + + if (qtyChanges > 0) + await Task.Run(() => finalizeLibrarySizeChange()); + logTime("importIntoDbAsync -- post finalizeLibrarySizeChange"); + + return newCount; + } + + private static int saveChanges(LibationContext context) { - logTime("importIntoDbAsync -- pre db"); - using var context = DbContexts.GetContext(); - var libraryBookImporter = new LibraryBookImporter(context); - var newCount = await Task.Run(() => libraryBookImporter.Import(importItems)); - logTime("importIntoDbAsync -- post Import()"); - var qtyChanges = context.SaveChanges(); - logTime("importIntoDbAsync -- post SaveChanges"); + try + { + return context.SaveChanges(); + } + catch (Microsoft.EntityFrameworkCore.DbUpdateException ex) + { + // DbUpdateException exceptions can wreck serilog. Condense it until we can find a better solution. I suspect the culpret is the "WithExceptionDetails" serilog extension - if (qtyChanges > 0) - await Task.Run(() => finalizeLibrarySizeChange()); - logTime("importIntoDbAsync -- post finalizeLibrarySizeChange"); + static string format(Exception ex) => $"\r\nMessage: {ex.Message}\r\nStack Trace:\r\n{ex.StackTrace}"; - return newCount; - } - #endregion + var msg = "Microsoft.EntityFrameworkCore.DbUpdateException"; + if (ex.InnerException is null) + throw new Exception($"{msg}{format(ex)}"); + throw new Exception( + $"{msg}{format(ex)}", + new Exception($"Inner Exception{format(ex.InnerException)}")); + } + } + #endregion - #region remove books - public static Task> RemoveBooksAsync(List idsToRemove) => Task.Run(() => removeBooks(idsToRemove)); + #region remove books + public static Task> RemoveBooksAsync(List idsToRemove) => Task.Run(() => removeBooks(idsToRemove)); private static List removeBooks(List idsToRemove) { using var context = DbContexts.GetContext(); diff --git a/DataLayer/EfClasses/Category.cs b/DataLayer/EfClasses/Category.cs index b97b4e5b..64af14db 100644 --- a/DataLayer/EfClasses/Category.cs +++ b/DataLayer/EfClasses/Category.cs @@ -18,7 +18,7 @@ namespace DataLayer public class Category { // Empty is a special case. use private ctor w/o validation - public static Category GetEmpty() => new Category { CategoryId = -1, AudibleCategoryId = "", Name = "" }; + public static Category GetEmpty() => new() { CategoryId = -1, AudibleCategoryId = "", Name = "" }; internal int CategoryId { get; private set; } public string AudibleCategoryId { get; private set; } diff --git a/DataLayer/EfClasses/Contributor.cs b/DataLayer/EfClasses/Contributor.cs index 99351e38..f050c9aa 100644 --- a/DataLayer/EfClasses/Contributor.cs +++ b/DataLayer/EfClasses/Contributor.cs @@ -7,7 +7,7 @@ namespace DataLayer public class Contributor { // Empty is a special case. use private ctor w/o validation - public static Contributor GetEmpty() => new Contributor { ContributorId = -1, Name = "" }; + public static Contributor GetEmpty() => new() { ContributorId = -1, Name = "" }; // contributors search links are just name with url-encoding. space can be + or %20 // author search link: /search?searchAuthor=Robert+Bevan diff --git a/DtoImporterService/BookImporter.cs b/DtoImporterService/BookImporter.cs index 406709da..e4f619ed 100644 --- a/DtoImporterService/BookImporter.cs +++ b/DtoImporterService/BookImporter.cs @@ -121,9 +121,7 @@ namespace DtoImporterService : item.Categories[1].CategoryId; // This should properly be SingleOrDefault() not FirstOrDefault(), but FirstOrDefault is defensive - var category - = DbContext.Categories.Local.FirstOrDefault(c => c.AudibleCategoryId == lastCategory) - ?? Category.GetEmpty(); + var category = DbContext.Categories.Local.FirstOrDefault(c => c.AudibleCategoryId == lastCategory); Book book; try diff --git a/DtoImporterService/CategoryImporter.cs b/DtoImporterService/CategoryImporter.cs index 09b8f95b..eeba9413 100644 --- a/DtoImporterService/CategoryImporter.cs +++ b/DtoImporterService/CategoryImporter.cs @@ -35,6 +35,9 @@ namespace DtoImporterService private void loadLocal_categories(List categoryIds) { + // must include default/empty/missing + categoryIds.Add(Category.GetEmpty().AudibleCategoryId); + var localIds = DbContext.Categories.Local.Select(c => c.AudibleCategoryId).ToList(); var remainingCategoryIds = categoryIds .Distinct() @@ -42,10 +45,8 @@ namespace DtoImporterService .ToList(); // load existing => local - // remember to include default/empty/missing - var emptyName = Contributor.GetEmpty().Name; if (remainingCategoryIds.Any()) - DbContext.Categories.Where(c => remainingCategoryIds.Contains(c.AudibleCategoryId) || c.Name == emptyName).ToList(); + DbContext.Categories.Where(c => remainingCategoryIds.Contains(c.AudibleCategoryId)).ToList(); } // only use after loading contributors => local