/// <summary> /// Synchronizes the items that exist in the source only. /// </summary> /// <param name="batchKeys">The keys of the items.</param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param> /// <returns></returns> private async Task SyncItemsInSourceOnlyBatchAsync(List <TKey> batchKeys, CancellationToken cancellationToken) { if (!batchKeys.Any()) { return; } switch (Configurations.SyncMode.ItemsInSourceOnly) { case SyncItemOperation.None: // do nothing break; case SyncItemOperation.Add: var comparisonResult = new ComparisonResult <TItem>(); comparisonResult.ItemsInSourceOnly.AddRange(await SourceProvider.GetAsync(batchKeys, cancellationToken).ConfigureAwait(false)); await SyncAsync(comparisonResult, cancellationToken).ConfigureAwait(false); break; case SyncItemOperation.Delete: BeforeDeletingItemsFromSourceAction?.Invoke(batchKeys); await SourceProvider.DeleteAsync(batchKeys, cancellationToken).ConfigureAwait(false); break; default: throw new NotSupportedException($"Not supported source {nameof(SyncItemOperation)} '{Configurations.SyncMode.ItemsInSourceOnly.ToString()}'."); } }
/// <summary> /// Compares the source and destination keys, and returns the comparison result. /// </summary> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param> /// <returns>The comparison result.</returns> public async Task <KeysComparisonResult <TKey> > CompareAsync(CancellationToken cancellationToken) { Validate(); var comparisonResult = new KeysComparisonResult <TKey>(); SortedSet <TKey> sourceSet = new SortedSet <TKey>() , destinationSet = new SortedSet <TKey>(); // Get entries from source and destination at the same time var tskSrc = Task.Run(async() => AddKeysToSet(sourceSet, await SourceProvider.GetAsync(cancellationToken).ConfigureAwait(false), "source list"), cancellationToken); var tskDest = Task.Run(async() => AddKeysToSet(destinationSet, await DestinationProvider.GetAsync(cancellationToken).ConfigureAwait(false), "destination list"), cancellationToken); await Task.WhenAll(tskSrc, tskDest).ConfigureAwait(false); // Compare keys foreach (var srcKey in sourceSet) { if (destinationSet.Remove(srcKey)) { comparisonResult.Matches.Add(srcKey); } else { comparisonResult.KeysInSourceOnly.Add(srcKey); } } foreach (var destKey in destinationSet) { comparisonResult.KeysInDestinationOnly.Add(destKey); } return(comparisonResult); }
/// <summary> /// Synchronizes the items that exist in the source and destination. /// </summary> /// <param name="batchKeys">The keys of the items.</param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param> /// <returns></returns> private async Task SyncMatchesBatchAsync(List <TKey> batchKeys, CancellationToken cancellationToken) { var srcTask = SourceProvider.GetAsync(batchKeys, cancellationToken); var dstTask = DestinationProvider.GetAsync(batchKeys, cancellationToken); await Task.WhenAll(srcTask, dstTask); // Compare var comparisonResult = await ComparerAgent <TKey, TItem> .Create() .Configure((c) => { c.AllowDuplicateItems = RuleAllowanceType.None; c.AllowDuplicateKeys = RuleAllowanceType.None; c.AllowNullableItems = RuleAllowanceType.None; }) .SetKeySelector(KeySelector) .SetCompareItemFunc(CompareItemFunc) .SetSourceProvider(srcTask.Result) .SetDestinationProvider(dstTask.Result) .CompareAsync(cancellationToken).ConfigureAwait(false); // Sync await SyncAsync(comparisonResult, cancellationToken).ConfigureAwait(false); }
/// <summary> /// Compares the source and destination items, and returns the comparison result. /// </summary> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work.</param> /// <returns>The comparison result.</returns> public async Task <ComparisonResult <TItem> > CompareAsync(CancellationToken cancellationToken) { Validate(); var comparisonResult = new ComparisonResult <TItem>(); Dictionary <TKey, List <TItem> > dicSrc = new Dictionary <TKey, List <TItem> >() , dicDest = new Dictionary <TKey, List <TItem> >(); List <TItem> nullableKeysSrcItems = new List <TItem>() , nullableKeysDestItems = new List <TItem>(); // Get entries from source and destination at the same time var tskSrc = Task.Run(async() => AddItemsToDictionary(dicSrc, nullableKeysSrcItems, await SourceProvider.GetAsync(cancellationToken).ConfigureAwait(false)), cancellationToken); var tskDest = Task.Run(async() => AddItemsToDictionary(dicDest, nullableKeysDestItems, await DestinationProvider.GetAsync(cancellationToken).ConfigureAwait(false)), cancellationToken); await Task.WhenAll(tskSrc, tskDest).ConfigureAwait(false); Validate(dicSrc, dicDest, nullableKeysSrcItems, nullableKeysDestItems); // Compare items that don't have null-able keys foreach (var srcKey in dicSrc.Keys) { var srcItems = dicSrc[srcKey]; if (dicDest.TryGetValue(srcKey, out var destItems)) { MatchItemsWithTheSameKey(comparisonResult, srcItems, destItems); } else { comparisonResult.ItemsInSourceOnly.AddRange(srcItems); } } var remainingDestItems = dicDest.Values.SelectMany(x => x).ToArray(); if (remainingDestItems.Any()) { comparisonResult.ItemsInDestinationOnly.AddRange(remainingDestItems); } // Compare items that have null-able keys MatchItemsWithTheSameKey(comparisonResult, nullableKeysSrcItems, nullableKeysDestItems); return(comparisonResult); }