NoTracking() to simplify confusing EF Core state. Tracking is now only used during mass import, not in UI

This commit is contained in:
Robert McRackan 2021-07-28 14:51:35 -04:00
parent 3c1db55a95
commit 85c18c8334
9 changed files with 31 additions and 28 deletions

View File

@ -104,8 +104,11 @@ namespace ApplicationServices
{ {
try try
{ {
book.UserDefinedItem.Tags = newTags; var udi = book.UserDefinedItem;
// Attach() NoTracking entities before SaveChanges()
udi.Tags = newTags;
context.Attach(udi).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
var qtyChanges = context.SaveChanges(); var qtyChanges = context.SaveChanges();
if (qtyChanges > 0) if (qtyChanges > 0)

View File

@ -11,7 +11,7 @@ namespace DataLayer
public static Book GetBook_Flat_NoTracking(this LibationContext context, string productId) public static Book GetBook_Flat_NoTracking(this LibationContext context, string productId)
=> context => context
.Books .Books
.AsNoTracking() .AsNoTrackingWithIdentityResolution()
.GetBook(productId); .GetBook(productId);
public static Book GetBook(this IQueryable<Book> books, string productId) public static Book GetBook(this IQueryable<Book> books, string productId)

View File

@ -6,25 +6,31 @@ namespace DataLayer
{ {
public static class LibraryQueries public static class LibraryQueries
{ {
public static List<LibraryBook> GetLibrary_Flat_WithTracking(this LibationContext context) //// tracking is a bad idea for main grid. it prevents anything else from updating entities unless getting them from the grid
=> context //public static List<LibraryBook> GetLibrary_Flat_WithTracking(this LibationContext context)
.Library // => context
.GetLibrary() // .Library
.ToList(); // .GetLibrary()
// .ToList();
public static List<LibraryBook> GetLibrary_Flat_NoTracking(this LibationContext context) public static List<LibraryBook> GetLibrary_Flat_NoTracking(this LibationContext context)
=> context => context
.Library .Library
.AsNoTracking() .AsNoTrackingWithIdentityResolution()
.GetLibrary() .GetLibrary()
.ToList(); .ToList();
public static LibraryBook GetLibraryBook_Flat_NoTracking(this LibationContext context, string productId) public static LibraryBook GetLibraryBook_Flat_NoTracking(this LibationContext context, string productId)
=> context => context
.Library .Library
.AsNoTracking() .AsNoTrackingWithIdentityResolution()
.GetLibraryBook(productId); .GetLibraryBook(productId);
public static LibraryBook GetLibraryBook(this IQueryable<LibraryBook> library, string productId)
=> library
.GetLibrary()
.SingleOrDefault(lb => lb.Book.AudibleProductId == productId);
/// <summary>This is still IQueryable. YOU MUST CALL ToList() YOURSELF</summary> /// <summary>This is still IQueryable. YOU MUST CALL ToList() YOURSELF</summary>
public static IQueryable<LibraryBook> GetLibrary(this IQueryable<LibraryBook> library) public static IQueryable<LibraryBook> GetLibrary(this IQueryable<LibraryBook> library)
=> library => library
@ -32,10 +38,5 @@ namespace DataLayer
.Include(le => le.Book).ThenInclude(b => b.SeriesLink).ThenInclude(sb => sb.Series) .Include(le => le.Book).ThenInclude(b => b.SeriesLink).ThenInclude(sb => sb.Series)
.Include(le => le.Book).ThenInclude(b => b.ContributorsLink).ThenInclude(c => c.Contributor) .Include(le => le.Book).ThenInclude(b => b.ContributorsLink).ThenInclude(c => c.Contributor)
.Include(le => le.Book).ThenInclude(b => b.Category).ThenInclude(c => c.ParentCategory); .Include(le => le.Book).ThenInclude(b => b.Category).ThenInclude(c => c.ParentCategory);
public static LibraryBook GetLibraryBook(this IQueryable<LibraryBook> library, string productId)
=> library
.GetLibrary()
.SingleOrDefault(le => le.Book.AudibleProductId == productId);
} }
} }

View File

@ -5,7 +5,6 @@ using Dinah.Core.Net.Http;
namespace FileLiberator namespace FileLiberator
{ {
// frustratingly copy pasta from DownloadableBase and DownloadPdf
// currently only used to download the .zip flies for upgrade // currently only used to download the .zip flies for upgrade
public class DownloadFile : IDownloadable public class DownloadFile : IDownloadable
{ {

View File

@ -22,11 +22,6 @@ namespace FileLiberator
return verifyDownload(libraryBook); return verifyDownload(libraryBook);
} }
private static StatusHandler verifyDownload(LibraryBook libraryBook)
=> !AudibleFileStorage.PDF.Exists(libraryBook.Book.AudibleProductId)
? new StatusHandler { "Downloaded PDF cannot be found" }
: new StatusHandler();
private static string getProposedDownloadFilePath(LibraryBook libraryBook) private static string getProposedDownloadFilePath(LibraryBook libraryBook)
{ {
// if audio file exists, get it's dir. else return base Book dir // if audio file exists, get it's dir. else return base Book dir
@ -44,6 +39,9 @@ namespace FileLiberator
return full; return full;
} }
private static string getdownloadUrl(LibraryBook libraryBook)
=> libraryBook?.Book?.Supplements?.FirstOrDefault()?.Url;
private async Task downloadPdfAsync(LibraryBook libraryBook, string proposedDownloadFilePath) private async Task downloadPdfAsync(LibraryBook libraryBook, string proposedDownloadFilePath)
{ {
var api = await GetApiAsync(libraryBook); var api = await GetApiAsync(libraryBook);
@ -55,7 +53,9 @@ namespace FileLiberator
(p) => client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, p)); (p) => client.DownloadFileAsync(downloadUrl, proposedDownloadFilePath, p));
} }
private static string getdownloadUrl(LibraryBook libraryBook) private static StatusHandler verifyDownload(LibraryBook libraryBook)
=> libraryBook?.Book?.Supplements?.FirstOrDefault()?.Url; => !AudibleFileStorage.PDF.Exists(libraryBook.Book.AudibleProductId)
? new StatusHandler { "Downloaded PDF cannot be found" }
: new StatusHandler();
} }
} }

View File

@ -25,10 +25,7 @@ namespace FileLiberator
public static LibraryBook GetSingleLibraryBook(string productId) public static LibraryBook GetSingleLibraryBook(string productId)
{ {
using var context = DbContexts.GetContext(); using var context = DbContexts.GetContext();
var libraryBook = context var libraryBook = context.GetLibraryBook_Flat_NoTracking(productId);
.Library
.GetLibrary()
.SingleOrDefault(lb => lb.Book.AudibleProductId == productId);
return libraryBook; return libraryBook;
} }

View File

@ -31,6 +31,9 @@ namespace FileManager
{ {
ensureCache(); ensureCache();
if (!tagsCollection.Any())
return;
// on initial reload, there's a huge benefit to adding to cache individually then updating the file only once // on initial reload, there's a huge benefit to adding to cache individually then updating the file only once
foreach ((string productId, string tags) in tagsCollection) foreach ((string productId, string tags) in tagsCollection)
cache[productId] = tags; cache[productId] = tags;

View File

@ -13,7 +13,7 @@
<!-- <PublishSingleFile>true</PublishSingleFile> --> <!-- <PublishSingleFile>true</PublishSingleFile> -->
<RuntimeIdentifier>win-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<Version>5.4.1.5</Version> <Version>5.4.2.1</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -338,7 +338,7 @@ namespace LibationWinForms
// transform into sorted GridEntry.s BEFORE binding // transform into sorted GridEntry.s BEFORE binding
// //
context = DbContexts.GetContext(); context = DbContexts.GetContext();
var lib = context.GetLibrary_Flat_WithTracking(); var lib = context.GetLibrary_Flat_NoTracking();
// if no data. hide all columns. return // if no data. hide all columns. return
if (!lib.Any()) if (!lib.Any())