using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore; namespace DataLayer { // only library importing should use tracking. All else should be NoTracking. // only library importing should directly query Book. All else should use LibraryBook public static class LibraryBookQueries { //// tracking is a bad idea for main grid. it prevents anything else from updating entities unless getting them from the grid //public static List GetLibrary_Flat_WithTracking(this LibationContext context) // => context // .Library // .GetLibrary() // .ToList(); public static List GetLibrary_Flat_NoTracking(this LibationContext context, bool includeParents = false) => context .LibraryBooks .AsNoTrackingWithIdentityResolution() .GetLibrary() .AsEnumerable() .Where(lb => !lb.Book.IsEpisodeParent() || includeParents) .ToList(); public static LibraryBook GetLibraryBook_Flat_NoTracking(this LibationContext context, string productId) => context .LibraryBooks .AsNoTrackingWithIdentityResolution() .GetLibraryBook(productId); public static LibraryBook GetLibraryBook(this IQueryable library, string productId) => library .GetLibrary() .SingleOrDefault(lb => lb.Book.AudibleProductId == productId); /// This is still IQueryable. YOU MUST CALL ToList() YOURSELF public static IQueryable GetLibrary(this IQueryable library) => library // owned items are always loaded. eg: book.UserDefinedItem, book.Supplements .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.Category).ThenInclude(c => c.ParentCategory); public static IEnumerable ParentedEpisodes(this IEnumerable libraryBooks) => libraryBooks.Where(lb => lb.Book.IsEpisodeParent()).SelectMany(s => libraryBooks.FindChildren(s)); public static IEnumerable FindOrphanedEpisodes(this IEnumerable libraryBooks) => libraryBooks .Where(lb => lb.Book.IsEpisodeChild()) .ExceptBy( libraryBooks .ParentedEpisodes() .Select(ge => ge.Book.AudibleProductId), ge => ge.Book.AudibleProductId); #nullable enable public static LibraryBook? FindSeriesParent(this IEnumerable libraryBooks, LibraryBook seriesEpisode) { if (seriesEpisode.Book.SeriesLink is null) return null; try { //Parent books will always have exactly 1 SeriesBook due to how //they are imported in ApiExtended.getChildEpisodesAsync() return libraryBooks.FirstOrDefault( lb => lb.Book.IsEpisodeParent() && seriesEpisode.Book.SeriesLink.Any( s => s.Series.AudibleSeriesId == lb.Book.SeriesLink.Single().Series.AudibleSeriesId)); } catch (System.Exception ex) { Serilog.Log.Error(ex, "Query error in {0}", nameof(FindSeriesParent)); return null; } } #nullable disable public static IEnumerable FindChildren(this IEnumerable bookList, LibraryBook parent) => bookList .Where( lb => lb.Book.IsEpisodeChild() && lb.Book.SeriesLink? .Any( s => s.Series.AudibleSeriesId == parent.Book.AudibleProductId ) == true ).ToList(); public static IEnumerable UnLiberated(this IEnumerable bookList) => bookList .Where( lb => lb.Book.UserDefinedItem.BookStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload || lb.Book.UserDefinedItem.PdfStatus is LiberatedStatus.NotLiberated or LiberatedStatus.PartialDownload ); } }