Index: Ringtoets/Common/src/Ringtoets.Common.Data/UpdateDataStrategies/UpdateDataStrategyBase.cs =================================================================== diff -u -re3ec5f4669022733a11c4c3070747331bf36056f -rc6b6a1a125535151416a5426d75472d045943d1a --- Ringtoets/Common/src/Ringtoets.Common.Data/UpdateDataStrategies/UpdateDataStrategyBase.cs (.../UpdateDataStrategyBase.cs) (revision e3ec5f4669022733a11c4c3070747331bf36056f) +++ Ringtoets/Common/src/Ringtoets.Common.Data/UpdateDataStrategies/UpdateDataStrategyBase.cs (.../UpdateDataStrategyBase.cs) (revision c6b6a1a125535151416a5426d75472d045943d1a) @@ -136,38 +136,22 @@ string sourceFilePath) { TTargetData[] importedObjects = importedDataCollection.ToArray(); - TTargetData[] objectsToBeAdded = GetObjectsToBeAdded(targetDataCollection, importedObjects).ToArray(); - TTargetData[] objectsToBeRemoved = GetObjectsToBeRemoved(targetDataCollection, importedObjects).ToArray(); - TTargetData[] objectsToBeUpdated = GetObjectsToBeUpdated(targetDataCollection, importedObjects).ToArray(); + var modification = new Modification(targetDataCollection, importedObjects, equalityComparer); + var affectedObjects = new List(); - if (objectsToBeAdded.Any() || objectsToBeRemoved.Any() || objectsToBeUpdated.Any()) + if (modification.HasUpdates()) { affectedObjects.Add(targetDataCollection); } - affectedObjects.AddRange(UpdateData(objectsToBeUpdated, importedObjects)); - affectedObjects.AddRange(RemoveData(objectsToBeRemoved)); + affectedObjects.AddRange(UpdateData(modification.ObjectsToBeUpdated.Values, importedObjects)); + affectedObjects.AddRange(RemoveData(modification.ObjectsToBeRemoved)); targetDataCollection.Clear(); - targetDataCollection.AddRange(objectsToBeUpdated.Union(objectsToBeAdded), sourceFilePath); + targetDataCollection.AddRange(modification.GetModifiedCollection(), sourceFilePath); return affectedObjects.Distinct(new ReferenceEqualityComparer()); } - private IEnumerable GetObjectsToBeRemoved(IEnumerable existingCollection, IEnumerable importedDataOjects) - { - return existingCollection.Except(importedDataOjects, equalityComparer); - } - - private IEnumerable GetObjectsToBeUpdated(IEnumerable existingCollection, IEnumerable importedDataObjects) - { - return existingCollection.Intersect(importedDataObjects, equalityComparer); - } - - private IEnumerable GetObjectsToBeAdded(IEnumerable existingCollection, IEnumerable importedDataObjects) - { - return importedDataObjects.Where(source => !existingCollection.Contains(source, equalityComparer)); - } - /// /// Updates all the objects and their dependent data that needs to be /// updated with data from the imported data collection. @@ -221,5 +205,129 @@ } return affectedObjects; } + + /// + /// Inner class for obtaining the modifications of an update action. + /// + private class Modification + { + /// + /// Creates a new instance of . + /// + /// The current collection of objects. + /// The collection of objects that were imported. + /// The comparer to test whether elements in + /// have a matching element in + /// . + public Modification(IEnumerable existingObjects, + IEnumerable updatedObjects, + IEqualityComparer equalityComparer) + { + TTargetData[] existingArray = existingObjects.ToArray(); + + var index = 0; + foreach (TTargetData importedObject in updatedObjects) + { + int existingObjectIndex = FindIndex(existingArray, importedObject, equalityComparer); + if (existingObjectIndex > -1) + { + ObjectsToBeUpdated.Add(index, existingArray[existingObjectIndex]); + existingArray[existingObjectIndex] = null; + } + else + { + ObjectsToBeAdded.Add(index, importedObject); + } + index++; + } + + ObjectsToBeRemoved = existingArray.Where(e => e != null); + } + + /// + /// Gets the objects that were updated. + /// + public Dictionary ObjectsToBeUpdated { get; } = new Dictionary(); + + /// + /// Gets the objects that were removed. + /// + public IEnumerable ObjectsToBeRemoved { get; } + + /// + /// Gets a collection of updated objects from the existing object collection and the + /// added objects from the imported object collection, in the same order that was + /// found in the imported object collection. + /// + /// An ordered collection of updated and added elements. + public IEnumerable GetModifiedCollection() + { + TTargetData[] remainingObjects = ObjectsToBeUpdated.Values.Union(ObjectsToBeAdded.Values).ToArray(); + int[] indices = GetElementOrder(); + + foreach (int i in Enumerable.Range(0, remainingObjects.Length)) + { + TTargetData x = remainingObjects[i]; + int j = i; + while (true) + { + int k = indices[j]; + indices[j] = j; + if (k == i) + { + break; + } + remainingObjects[j] = remainingObjects[k]; + j = k; + } + remainingObjects[j] = x; + } + + return remainingObjects; + } + + /// + /// Finds out whether there was a difference between the existing and the imported + /// object collections. + /// + /// + public bool HasUpdates() + { + return ObjectsToBeRemoved.Any() || ObjectsToBeAdded.Any() || ObjectsToBeUpdated.Any(); + } + + private Dictionary ObjectsToBeAdded { get; } = new Dictionary(); + + private int[] GetElementOrder() + { + int[] keys = ObjectsToBeUpdated.Keys.Union(ObjectsToBeAdded.Keys).ToArray(); + + int orderLength = keys.Length; + var order = new int[orderLength]; + for (var valueToInsert = 0; valueToInsert < orderLength; valueToInsert++) + { + order[keys[valueToInsert]] = valueToInsert; + } + + return order; + } + + private static int FindIndex(TTargetData[] collectionToLookIn, TTargetData objectToFind, IEqualityComparer equalityComparer) + { + if (objectToFind == null) + { + throw new ArgumentNullException(nameof(objectToFind)); + } + for (var i = 0; i < collectionToLookIn.Length; i++) + { + TTargetData targetData = collectionToLookIn[i]; + if (targetData != null && equalityComparer.Equals(targetData, objectToFind)) + { + return i; + } + } + return -1; + } + } } } \ No newline at end of file