parent
f5c1858d4c
commit
0b7a42ee3b
@ -1,160 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
|
||||
namespace NzbDrone.Core.Music
|
||||
{
|
||||
public interface IAddAlbumService
|
||||
{
|
||||
Album AddAlbum(Album newAlbum);
|
||||
List<Album> AddAlbums(List<Album> newAlbums);
|
||||
}
|
||||
|
||||
public class AddAlbumService : IAddAlbumService
|
||||
{
|
||||
private readonly IAlbumService _albumService;
|
||||
private readonly IReleaseService _releaseService;
|
||||
private readonly IProvideAlbumInfo _albumInfo;
|
||||
private readonly IArtistMetadataRepository _artistMetadataRepository;
|
||||
private readonly IRefreshTrackService _refreshTrackService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public AddAlbumService(IAlbumService albumService,
|
||||
IReleaseService releaseService,
|
||||
IProvideAlbumInfo albumInfo,
|
||||
IArtistMetadataRepository artistMetadataRepository,
|
||||
IRefreshTrackService refreshTrackService,
|
||||
Logger logger)
|
||||
{
|
||||
_albumService = albumService;
|
||||
_releaseService = releaseService;
|
||||
_albumInfo = albumInfo;
|
||||
_artistMetadataRepository = artistMetadataRepository;
|
||||
_refreshTrackService = refreshTrackService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<AlbumRelease> AddAlbumReleases(Album album)
|
||||
{
|
||||
var remoteReleases = album.AlbumReleases.Value.DistinctBy(m => m.ForeignReleaseId).ToList();
|
||||
var existingReleases = _releaseService.GetReleasesForRefresh(album.Id, remoteReleases.Select(x => x.ForeignReleaseId));
|
||||
var newReleaseList = new List<AlbumRelease>();
|
||||
var updateReleaseList = new List<AlbumRelease>();
|
||||
|
||||
foreach (var release in remoteReleases)
|
||||
{
|
||||
release.AlbumId = album.Id;
|
||||
release.Album = album;
|
||||
var releaseToRefresh = existingReleases.SingleOrDefault(r => r.ForeignReleaseId == release.ForeignReleaseId);
|
||||
|
||||
if (releaseToRefresh != null)
|
||||
{
|
||||
existingReleases.Remove(releaseToRefresh);
|
||||
|
||||
// copy across the db keys and check for equality
|
||||
release.Id = releaseToRefresh.Id;
|
||||
release.AlbumId = releaseToRefresh.AlbumId;
|
||||
|
||||
updateReleaseList.Add(release);
|
||||
}
|
||||
else
|
||||
{
|
||||
newReleaseList.Add(release);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure only one release is monitored
|
||||
remoteReleases.ForEach(x => x.Monitored = false);
|
||||
remoteReleases.OrderByDescending(x => x.TrackCount).First().Monitored = true;
|
||||
Ensure.That(remoteReleases.Count(x => x.Monitored) == 1).IsTrue();
|
||||
|
||||
// Since this is a new album, we can't be deleting any existing releases
|
||||
_releaseService.UpdateMany(updateReleaseList);
|
||||
_releaseService.InsertMany(newReleaseList);
|
||||
|
||||
return remoteReleases;
|
||||
}
|
||||
|
||||
private Album AddAlbum(Tuple<string, Album, List<ArtistMetadata>> skyHookData)
|
||||
{
|
||||
var newAlbum = skyHookData.Item2;
|
||||
|
||||
if (newAlbum.AlbumReleases.Value.Count == 0)
|
||||
{
|
||||
_logger.Debug($"Skipping album with no valid releases {newAlbum}");
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.ProgressInfo("Adding Album {0}", newAlbum.Title);
|
||||
|
||||
_artistMetadataRepository.UpsertMany(skyHookData.Item3);
|
||||
newAlbum.ArtistMetadata = _artistMetadataRepository.FindById(skyHookData.Item1);
|
||||
newAlbum.ArtistMetadataId = newAlbum.ArtistMetadata.Value.Id;
|
||||
|
||||
_albumService.AddAlbum(newAlbum);
|
||||
AddAlbumReleases(newAlbum);
|
||||
|
||||
_refreshTrackService.RefreshTrackInfo(newAlbum, false);
|
||||
|
||||
return newAlbum;
|
||||
}
|
||||
|
||||
public Album AddAlbum(Album newAlbum)
|
||||
{
|
||||
Ensure.That(newAlbum, () => newAlbum).IsNotNull();
|
||||
|
||||
var tuple = AddSkyhookData(newAlbum);
|
||||
|
||||
return AddAlbum(tuple);
|
||||
}
|
||||
|
||||
public List<Album> AddAlbums(List<Album> newAlbums)
|
||||
{
|
||||
var added = DateTime.UtcNow;
|
||||
var albumsToAdd = new List<Album>();
|
||||
|
||||
foreach (var newAlbum in newAlbums)
|
||||
{
|
||||
var tuple = AddSkyhookData(newAlbum);
|
||||
tuple.Item2.Added = added;
|
||||
tuple.Item2.LastInfoSync = added;
|
||||
|
||||
albumsToAdd.Add(AddAlbum(tuple));
|
||||
}
|
||||
|
||||
return albumsToAdd;
|
||||
}
|
||||
|
||||
private Tuple<string, Album, List<ArtistMetadata>> AddSkyhookData(Album newAlbum)
|
||||
{
|
||||
Tuple<string, Album, List<ArtistMetadata>> tuple;
|
||||
|
||||
try
|
||||
{
|
||||
tuple = _albumInfo.GetAlbumInfo(newAlbum.ForeignAlbumId);
|
||||
}
|
||||
catch (AlbumNotFoundException)
|
||||
{
|
||||
_logger.Error("LidarrId {1} was not found, it may have been removed from Lidarr.", newAlbum.ForeignAlbumId);
|
||||
|
||||
throw new ValidationException(new List<ValidationFailure>
|
||||
{
|
||||
new ValidationFailure("MusicBrainzId", "An album with this ID was not found", newAlbum.ForeignAlbumId)
|
||||
});
|
||||
}
|
||||
|
||||
tuple.Item2.Monitored = newAlbum.Monitored;
|
||||
tuple.Item2.ProfileId = newAlbum.ProfileId;
|
||||
|
||||
return tuple;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace NzbDrone.Core.Music
|
||||
{
|
||||
public interface IRefreshAlbumReleaseService
|
||||
{
|
||||
bool RefreshEntityInfo(AlbumRelease entity, List<AlbumRelease> remoteEntityList, bool forceChildRefresh, bool forceUpdateFileTags);
|
||||
bool RefreshEntityInfo(List<AlbumRelease> releases, List<AlbumRelease> remoteEntityList, bool forceChildRefresh, bool forceUpdateFileTags);
|
||||
}
|
||||
|
||||
public class RefreshAlbumReleaseService : RefreshEntityServiceBase<AlbumRelease, Track>, IRefreshAlbumReleaseService
|
||||
{
|
||||
private readonly IReleaseService _releaseService;
|
||||
private readonly IRefreshTrackService _refreshTrackService;
|
||||
private readonly ITrackService _trackService;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RefreshAlbumReleaseService(IReleaseService releaseService,
|
||||
IArtistMetadataRepository artistMetadataRepository,
|
||||
IRefreshTrackService refreshTrackService,
|
||||
ITrackService trackService,
|
||||
IMediaFileService mediaFileService,
|
||||
Logger logger)
|
||||
: base(logger, artistMetadataRepository)
|
||||
{
|
||||
_releaseService = releaseService;
|
||||
_trackService = trackService;
|
||||
_refreshTrackService = refreshTrackService;
|
||||
_mediaFileService = mediaFileService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
protected override RemoteData GetRemoteData(AlbumRelease local, List<AlbumRelease> remote)
|
||||
{
|
||||
var result = new RemoteData();
|
||||
result.Entity = remote.SingleOrDefault(x => x.ForeignReleaseId == local.ForeignReleaseId || x.OldForeignReleaseIds.Contains(local.ForeignReleaseId));
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override bool IsMerge(AlbumRelease local, AlbumRelease remote)
|
||||
{
|
||||
return local.ForeignReleaseId != remote.ForeignReleaseId;
|
||||
}
|
||||
|
||||
protected override UpdateResult UpdateEntity(AlbumRelease local, AlbumRelease remote)
|
||||
{
|
||||
if (local.Equals(remote))
|
||||
{
|
||||
return UpdateResult.None;
|
||||
}
|
||||
|
||||
local.OldForeignReleaseIds = remote.OldForeignReleaseIds;
|
||||
local.Title = remote.Title;
|
||||
local.Status = remote.Status;
|
||||
local.Duration = remote.Duration;
|
||||
local.Label = remote.Label;
|
||||
local.Disambiguation = remote.Disambiguation;
|
||||
local.Country = remote.Country;
|
||||
local.ReleaseDate = remote.ReleaseDate;
|
||||
local.Media = remote.Media;
|
||||
local.TrackCount = remote.TrackCount;
|
||||
|
||||
return UpdateResult.UpdateTags;
|
||||
}
|
||||
|
||||
protected override AlbumRelease GetEntityByForeignId(AlbumRelease local)
|
||||
{
|
||||
return _releaseService.GetReleaseByForeignReleaseId(local.ForeignReleaseId);
|
||||
}
|
||||
|
||||
protected override void SaveEntity(AlbumRelease local)
|
||||
{
|
||||
_releaseService.UpdateMany(new List<AlbumRelease> { local });
|
||||
}
|
||||
|
||||
protected override void DeleteEntity(AlbumRelease local, bool deleteFiles)
|
||||
{
|
||||
_releaseService.DeleteMany(new List<AlbumRelease> { local });
|
||||
}
|
||||
|
||||
protected override List<Track> GetRemoteChildren(AlbumRelease remote)
|
||||
{
|
||||
return remote.Tracks.Value.DistinctBy(m => m.ForeignTrackId).ToList();
|
||||
}
|
||||
|
||||
protected override List<Track> GetLocalChildren(AlbumRelease entity, List<Track> remoteChildren)
|
||||
{
|
||||
return _trackService.GetTracksForRefresh(entity.Id,
|
||||
remoteChildren.Select(x => x.ForeignTrackId)
|
||||
.Concat(remoteChildren.SelectMany(x => x.OldForeignTrackIds)));
|
||||
}
|
||||
|
||||
protected override Tuple<Track, List<Track> > GetMatchingExistingChildren(List<Track> existingChildren, Track remote)
|
||||
{
|
||||
var existingChild = existingChildren.SingleOrDefault(x => x.ForeignTrackId == remote.ForeignTrackId);
|
||||
var mergeChildren = existingChildren.Where(x => remote.OldForeignTrackIds.Contains(x.ForeignTrackId)).ToList();
|
||||
return Tuple.Create(existingChild, mergeChildren);
|
||||
}
|
||||
|
||||
protected override void PrepareNewChild(Track child, AlbumRelease entity)
|
||||
{
|
||||
child.AlbumReleaseId = entity.Id;
|
||||
child.AlbumRelease = entity;
|
||||
child.ArtistMetadataId = child.ArtistMetadata.Value.Id;
|
||||
|
||||
// make sure title is not null
|
||||
child.Title = child.Title ?? "Unknown";
|
||||
}
|
||||
|
||||
protected override void PrepareExistingChild(Track local, Track remote, AlbumRelease entity)
|
||||
{
|
||||
local.AlbumRelease = entity;
|
||||
local.AlbumReleaseId = entity.Id;
|
||||
local.ArtistMetadataId = remote.ArtistMetadata.Value.Id;
|
||||
remote.Id = local.Id;
|
||||
remote.TrackFileId = local.TrackFileId;
|
||||
remote.AlbumReleaseId = local.AlbumReleaseId;
|
||||
remote.ArtistMetadataId = local.ArtistMetadataId;
|
||||
}
|
||||
|
||||
protected override void AddChildren(List<Track> children)
|
||||
{
|
||||
_trackService.InsertMany(children);
|
||||
}
|
||||
|
||||
protected override bool RefreshChildren(SortedChildren localChildren, List<Track> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||
{
|
||||
return _refreshTrackService.RefreshTrackInfo(localChildren.Added, localChildren.Updated, localChildren.Merged, localChildren.Deleted, localChildren.UpToDate, remoteChildren, forceUpdateFileTags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,277 @@
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.Music
|
||||
{
|
||||
public abstract class RefreshEntityServiceBase<Entity, Child>
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly IArtistMetadataRepository _artistMetadataRepository;
|
||||
|
||||
public RefreshEntityServiceBase(Logger logger,
|
||||
IArtistMetadataRepository artistMetadataRepository)
|
||||
{
|
||||
_logger = logger;
|
||||
_artistMetadataRepository = artistMetadataRepository;
|
||||
}
|
||||
|
||||
public enum UpdateResult
|
||||
{
|
||||
None,
|
||||
Standard,
|
||||
UpdateTags
|
||||
};
|
||||
|
||||
public class SortedChildren
|
||||
{
|
||||
public SortedChildren()
|
||||
{
|
||||
UpToDate = new List<Child>();
|
||||
Added = new List<Child>();
|
||||
Updated = new List<Child>();
|
||||
Merged = new List<Tuple<Child, Child> >();
|
||||
Deleted = new List<Child>();
|
||||
}
|
||||
|
||||
public List<Child> UpToDate { get; set; }
|
||||
public List<Child> Added { get; set; }
|
||||
public List<Child> Updated { get; set; }
|
||||
public List<Tuple<Child, Child> > Merged { get; set; }
|
||||
public List<Child> Deleted { get; set; }
|
||||
|
||||
public List<Child> All => UpToDate.Concat(Added).Concat(Updated).Concat(Merged.Select(x => x.Item1)).Concat(Deleted).ToList();
|
||||
public List<Child> Future => UpToDate.Concat(Added).Concat(Updated).ToList();
|
||||
public List<Child> Old => Merged.Select(x => x.Item1).Concat(Deleted).ToList();
|
||||
}
|
||||
|
||||
public class RemoteData
|
||||
{
|
||||
public Entity Entity { get; set; }
|
||||
public List<ArtistMetadata> Metadata { get; set; }
|
||||
}
|
||||
|
||||
protected virtual void LogProgress(Entity local)
|
||||
{
|
||||
}
|
||||
|
||||
protected abstract RemoteData GetRemoteData(Entity local, List<Entity> remote);
|
||||
|
||||
protected virtual void EnsureNewParent(Entity local, Entity remote)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
protected abstract bool IsMerge(Entity local, Entity remote);
|
||||
|
||||
protected virtual bool ShouldDelete(Entity local)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract UpdateResult UpdateEntity(Entity local, Entity remote);
|
||||
|
||||
protected virtual UpdateResult MoveEntity(Entity local, Entity remote)
|
||||
{
|
||||
return UpdateEntity(local, remote);
|
||||
}
|
||||
|
||||
protected virtual UpdateResult MergeEntity(Entity local, Entity target, Entity remote)
|
||||
{
|
||||
DeleteEntity(local, true);
|
||||
return UpdateResult.UpdateTags;
|
||||
}
|
||||
|
||||
protected abstract Entity GetEntityByForeignId(Entity local);
|
||||
protected abstract void SaveEntity(Entity local);
|
||||
protected abstract void DeleteEntity(Entity local, bool deleteFiles);
|
||||
|
||||
protected abstract List<Child> GetRemoteChildren(Entity remote);
|
||||
protected abstract List<Child> GetLocalChildren(Entity entity, List<Child> remoteChildren);
|
||||
protected abstract Tuple<Child, List<Child> > GetMatchingExistingChildren(List<Child> existingChildren, Child remote);
|
||||
|
||||
protected abstract void PrepareNewChild(Child remoteChild, Entity entity);
|
||||
protected abstract void PrepareExistingChild(Child existingChild, Child remoteChild, Entity entity);
|
||||
protected abstract void AddChildren(List<Child> children);
|
||||
protected abstract bool RefreshChildren(SortedChildren localChildren, List<Child> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags);
|
||||
|
||||
protected virtual void PublishEntityUpdatedEvent(Entity entity)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void PublishChildrenUpdatedEvent(Entity entity, List<Child> newChildren, List<Child> updateChildren)
|
||||
{
|
||||
}
|
||||
|
||||
public bool RefreshEntityInfo(Entity local, List<Entity> remoteList, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||
{
|
||||
bool updated = false;
|
||||
|
||||
LogProgress(local);
|
||||
|
||||
var data = GetRemoteData(local, remoteList);
|
||||
var remote = data.Entity;
|
||||
|
||||
if (remote == null)
|
||||
{
|
||||
if (ShouldDelete(local))
|
||||
{
|
||||
_logger.Warn($"{typeof(Entity).Name} {local} not found in metadata and is being deleted");
|
||||
DeleteEntity(local, true);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Error($"{typeof(Entity).Name} {local} was not found, it may have been removed from Metadata sources.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.Metadata != null)
|
||||
{
|
||||
var metadataResult = UpdateArtistMetadata(data.Metadata);
|
||||
updated |= metadataResult >= UpdateResult.Standard;
|
||||
forceUpdateFileTags |= metadataResult == UpdateResult.UpdateTags;
|
||||
}
|
||||
|
||||
// Validate that the parent object exists (remote data might specify a different one)
|
||||
EnsureNewParent(local, remote);
|
||||
|
||||
UpdateResult result;
|
||||
if (IsMerge(local, remote))
|
||||
{
|
||||
// get entity we're merging into
|
||||
var target = GetEntityByForeignId(remote);
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
_logger.Trace($"Moving {typeof(Entity).Name} {local} to {remote}");
|
||||
result = MoveEntity(local, remote);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Trace($"Merging {typeof(Entity).Name} {local} into {target}");
|
||||
result = MergeEntity(local, target, remote);
|
||||
|
||||
// having merged local into target, do update for target using remote
|
||||
local = target;
|
||||
}
|
||||
|
||||
// Save the entity early so that children see the updated ids
|
||||
SaveEntity(local);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Trace($"Updating {typeof(Entity).Name} {local}");
|
||||
result = UpdateEntity(local, remote);
|
||||
}
|
||||
|
||||
updated |= result >= UpdateResult.Standard;
|
||||
forceUpdateFileTags |= result == UpdateResult.UpdateTags;
|
||||
|
||||
_logger.Trace($"updated: {updated} forceUpdateFileTags: {forceUpdateFileTags}");
|
||||
|
||||
var remoteChildren = GetRemoteChildren(remote);
|
||||
updated |= SortChildren(local, remoteChildren, forceChildRefresh, forceUpdateFileTags);
|
||||
|
||||
// Do this last so entity only marked as refreshed if refresh of children completed successfully
|
||||
_logger.Trace($"Saving {typeof(Entity).Name} {local}");
|
||||
SaveEntity(local);
|
||||
|
||||
if (updated)
|
||||
{
|
||||
PublishEntityUpdatedEvent(local);
|
||||
}
|
||||
|
||||
_logger.Debug($"Finished {typeof(Entity).Name} refresh for {local}");
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
public UpdateResult UpdateArtistMetadata(List<ArtistMetadata> data)
|
||||
{
|
||||
var remoteMetadata = data.DistinctBy(x => x.ForeignArtistId).ToList();
|
||||
var updated = _artistMetadataRepository.UpsertMany(data);
|
||||
return updated ? UpdateResult.UpdateTags : UpdateResult.None;
|
||||
}
|
||||
|
||||
public bool RefreshEntityInfo(List<Entity> localList, List<Entity> remoteList, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||
{
|
||||
bool updated = false;
|
||||
foreach (var entity in localList)
|
||||
{
|
||||
updated |= RefreshEntityInfo(entity, remoteList, forceChildRefresh, forceUpdateFileTags);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
protected bool SortChildren(Entity entity, List<Child> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||
{
|
||||
// Get existing children (and children to be) from the database
|
||||
var localChildren = GetLocalChildren(entity, remoteChildren);
|
||||
|
||||
var sortedChildren = new SortedChildren();
|
||||
sortedChildren.Deleted.AddRange(localChildren);
|
||||
|
||||
// Cycle through children
|
||||
foreach (var remoteChild in remoteChildren)
|
||||
{
|
||||
// Check for child in existing children, if not set properties and add to new list
|
||||
var tuple = GetMatchingExistingChildren(localChildren, remoteChild);
|
||||
var existingChild = tuple.Item1;
|
||||
var mergedChildren = tuple.Item2;
|
||||
|
||||
if (existingChild != null)
|
||||
{
|
||||
sortedChildren.Deleted.Remove(existingChild);
|
||||
|
||||
PrepareExistingChild(existingChild, remoteChild, entity);
|
||||
|
||||
if (existingChild.Equals(remoteChild))
|
||||
{
|
||||
sortedChildren.UpToDate.Add(existingChild);
|
||||
}
|
||||
else
|
||||
{
|
||||
sortedChildren.Updated.Add(existingChild);
|
||||
}
|
||||
|
||||
// note the children that are going to be merged into existingChild
|
||||
foreach (var child in mergedChildren)
|
||||
{
|
||||
sortedChildren.Merged.Add(Tuple.Create(child, existingChild));
|
||||
sortedChildren.Deleted.Remove(child);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PrepareNewChild(remoteChild, entity);
|
||||
sortedChildren.Added.Add(remoteChild);
|
||||
|
||||
// note the children that will be merged into remoteChild (once added)
|
||||
foreach (var child in mergedChildren)
|
||||
{
|
||||
sortedChildren.Merged.Add(Tuple.Create(child, existingChild));
|
||||
sortedChildren.Deleted.Remove(child);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Debug("{0} {1} {2}s up to date. Adding {3}, Updating {4}, Merging {5}, Deleting {6}.",
|
||||
entity, sortedChildren.UpToDate.Count, typeof(Child).Name.ToLower(),
|
||||
sortedChildren.Added.Count, sortedChildren.Updated.Count, sortedChildren.Merged.Count, sortedChildren.Deleted.Count);
|
||||
|
||||
// Add in the new children (we have checked that foreign IDs don't clash)
|
||||
AddChildren(sortedChildren.Added);
|
||||
|
||||
// now trigger updates
|
||||
var updated = RefreshChildren(sortedChildren, remoteChildren, forceChildRefresh, forceUpdateFileTags);
|
||||
|
||||
PublishChildrenUpdatedEvent(entity, sortedChildren.Added, sortedChildren.Updated);
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue