From fa253244639b3ff9a74978a753e20d9d3f9232f5 Mon Sep 17 00:00:00 2001 From: ta264 Date: Tue, 30 Mar 2021 21:24:41 +0100 Subject: [PATCH] Fixed: Refreshing / Deleting Series --- src/NzbDrone.Core/Books/Model/Series.cs | 3 ++ .../Repositories/SeriesBookLinkRepository.cs | 14 +++++++- .../Books/Services/RefreshSeriesService.cs | 14 ++++++-- .../Books/Services/SeriesBookLinkService.cs | 17 ++++++++- src/NzbDrone.Core/Datastore/TableMapping.cs | 1 + .../Housekeepers/CleanupOrphanedEditions.cs | 28 +++++++++++++++ .../CleanupOrphanedSeriesBookLinks.cs | 35 +++++++++++++++++++ 7 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEditions.cs create mode 100644 src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedSeriesBookLinks.cs diff --git a/src/NzbDrone.Core/Books/Model/Series.cs b/src/NzbDrone.Core/Books/Model/Series.cs index d93230807..1f9d69153 100644 --- a/src/NzbDrone.Core/Books/Model/Series.cs +++ b/src/NzbDrone.Core/Books/Model/Series.cs @@ -20,6 +20,9 @@ namespace NzbDrone.Core.Books [MemberwiseEqualityIgnore] public LazyLoaded> Books { get; set; } + // A placeholder used in refresh only + public string ForeignAuthorId { get; set; } + public override string ToString() { return string.Format("[{0}][{1}]", ForeignSeriesId.NullSafe(), Title.NullSafe()); diff --git a/src/NzbDrone.Core/Books/Repositories/SeriesBookLinkRepository.cs b/src/NzbDrone.Core/Books/Repositories/SeriesBookLinkRepository.cs index 9f9a9fb55..d434ef235 100644 --- a/src/NzbDrone.Core/Books/Repositories/SeriesBookLinkRepository.cs +++ b/src/NzbDrone.Core/Books/Repositories/SeriesBookLinkRepository.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Datastore; using NzbDrone.Core.Messaging.Events; @@ -8,6 +8,7 @@ namespace NzbDrone.Core.Books public interface ISeriesBookLinkRepository : IBasicRepository { List GetLinksBySeries(int seriesId); + List GetLinksBySeriesAndAuthor(int seriesId, string foreignAuthorId); List GetLinksByBook(List bookIds); } @@ -23,6 +24,17 @@ namespace NzbDrone.Core.Books return Query(x => x.SeriesId == seriesId); } + public List GetLinksBySeriesAndAuthor(int seriesId, string foreignAuthorId) + { + return _database.Query( + Builder() + .Join((l, b) => l.BookId == b.Id) + .Join((b, a) => b.AuthorMetadataId == a.Id) + .Where(x => x.SeriesId == seriesId) + .Where(a => a.ForeignAuthorId == foreignAuthorId)) + .ToList(); + } + public List GetLinksByBook(List bookIds) { return _database.QueryJoined( diff --git a/src/NzbDrone.Core/Books/Services/RefreshSeriesService.cs b/src/NzbDrone.Core/Books/Services/RefreshSeriesService.cs index 450335284..2fefe9174 100644 --- a/src/NzbDrone.Core/Books/Services/RefreshSeriesService.cs +++ b/src/NzbDrone.Core/Books/Services/RefreshSeriesService.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using NLog; using NzbDrone.Common.Extensions; -using NzbDrone.Common.Serializer; namespace NzbDrone.Core.Books { @@ -73,7 +72,15 @@ namespace NzbDrone.Core.Books protected override void DeleteEntity(Series local, bool deleteFiles) { - _seriesService.Delete(local.Id); + _logger.Trace($"Removing links for series {local} author {local.ForeignAuthorId}"); + var children = GetLocalChildren(local, null); + _linkService.DeleteMany(children); + + if (!_linkService.GetLinksBySeries(local.Id).Any()) + { + _logger.Trace($"Series {local} has no links remaining, removing"); + _seriesService.Delete(local.Id); + } } protected override List GetRemoteChildren(Series local, Series remote) @@ -83,7 +90,7 @@ namespace NzbDrone.Core.Books protected override List GetLocalChildren(Series entity, List remoteChildren) { - return _linkService.GetLinksBySeries(entity.Id); + return _linkService.GetLinksBySeriesAndAuthor(entity.Id, entity.ForeignAuthorId); } protected override Tuple> GetMatchingExistingChildren(List existingChildren, SeriesBookLink remote) @@ -155,6 +162,7 @@ namespace NzbDrone.Core.Books foreach (var item in all) { + item.ForeignAuthorId = remoteData.ForeignAuthorId; updated |= RefreshEntityInfo(item, remoteSeries, remoteData, true, forceUpdateFileTags, null); } diff --git a/src/NzbDrone.Core/Books/Services/SeriesBookLinkService.cs b/src/NzbDrone.Core/Books/Services/SeriesBookLinkService.cs index f3c32c3b4..80093f113 100644 --- a/src/NzbDrone.Core/Books/Services/SeriesBookLinkService.cs +++ b/src/NzbDrone.Core/Books/Services/SeriesBookLinkService.cs @@ -1,17 +1,21 @@ using System.Collections.Generic; +using NzbDrone.Core.Books.Events; +using NzbDrone.Core.Messaging.Events; namespace NzbDrone.Core.Books { public interface ISeriesBookLinkService { List GetLinksBySeries(int seriesId); + List GetLinksBySeriesAndAuthor(int seriesId, string foreignAuthorId); List GetLinksByBook(List bookIds); void InsertMany(List model); void UpdateMany(List model); void DeleteMany(List model); } - public class SeriesBookLinkService : ISeriesBookLinkService + public class SeriesBookLinkService : ISeriesBookLinkService, + IHandle { private readonly ISeriesBookLinkRepository _repo; @@ -25,6 +29,11 @@ namespace NzbDrone.Core.Books return _repo.GetLinksBySeries(seriesId); } + public List GetLinksBySeriesAndAuthor(int seriesId, string foreignAuthorId) + { + return _repo.GetLinksBySeriesAndAuthor(seriesId, foreignAuthorId); + } + public List GetLinksByBook(List bookIds) { return _repo.GetLinksByBook(bookIds); @@ -44,5 +53,11 @@ namespace NzbDrone.Core.Books { _repo.DeleteMany(model); } + + public void Handle(BookDeletedEvent message) + { + var links = GetLinksByBook(new List { message.Book.Id }); + DeleteMany(links); + } } } diff --git a/src/NzbDrone.Core/Datastore/TableMapping.cs b/src/NzbDrone.Core/Datastore/TableMapping.cs index 3a49c1c57..dc1ba9d33 100644 --- a/src/NzbDrone.Core/Datastore/TableMapping.cs +++ b/src/NzbDrone.Core/Datastore/TableMapping.cs @@ -105,6 +105,7 @@ namespace NzbDrone.Core.Datastore .LazyLoad(a => a.Books, (db, a) => db.Query(new SqlBuilder().Where(rg => rg.AuthorMetadataId == a.Id)).ToList(), a => a.Id > 0); Mapper.Entity("Series").RegisterModel() + .Ignore(s => s.ForeignAuthorId) .LazyLoad(s => s.LinkItems, (db, series) => db.Query(new SqlBuilder().Where(s => s.SeriesId == series.Id)).ToList(), s => s.Id > 0) diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEditions.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEditions.cs new file mode 100644 index 000000000..25159bc5d --- /dev/null +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedEditions.cs @@ -0,0 +1,28 @@ +using Dapper; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.Housekeeping.Housekeepers +{ + public class CleanupOrphanedEditions : IHousekeepingTask + { + private readonly IMainDatabase _database; + + public CleanupOrphanedEditions(IMainDatabase database) + { + _database = database; + } + + public void Clean() + { + using (var mapper = _database.OpenConnection()) + { + mapper.Execute(@"DELETE FROM Editions + WHERE Id IN ( + SELECT Editions.Id FROM Editions + LEFT OUTER JOIN Books + ON Editions.BookId = Books.Id + WHERE Books.Id IS NULL)"); + } + } + } +} diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedSeriesBookLinks.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedSeriesBookLinks.cs new file mode 100644 index 000000000..8a2d4c778 --- /dev/null +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedSeriesBookLinks.cs @@ -0,0 +1,35 @@ +using Dapper; +using NzbDrone.Core.Datastore; + +namespace NzbDrone.Core.Housekeeping.Housekeepers +{ + public class CleanupOrphanedSeriesBookLinks : IHousekeepingTask + { + private readonly IMainDatabase _database; + + public CleanupOrphanedSeriesBookLinks(IMainDatabase database) + { + _database = database; + } + + public void Clean() + { + using (var mapper = _database.OpenConnection()) + { + mapper.Execute(@"DELETE FROM SeriesBookLinks + WHERE Id IN ( + SELECT SeriesBookLinks.Id FROM SeriesBookLinks + LEFT OUTER JOIN Books + ON SeriesBookLinks.BookId = Books.Id + WHERE Books.Id IS NULL)"); + + mapper.Execute(@"DELETE FROM SeriesBookLinks + WHERE Id IN ( + SELECT SeriesBookLinks.Id FROM SeriesBookLinks + LEFT OUTER JOIN Series + ON SeriesBookLinks.SeriesId = Series.Id + WHERE Series.Id IS NULL)"); + } + } + } +}