//public static void MergeTracking<TEntity>(this System.Collections.IEnumerable target, System.Collections.IEnumerable source) //{ // //Go through the new data and apply any modifications to the target. // foreach (ITrackableObject targetItem in target) // { // ITrackableObject sourceItem = null; // if (source != null) // sourceItem = source.FirstOrDefault(item => item.Id == targetItem.Id); // if (sourceItem != null) // { // targetItem.MergeTracking(sourceItem); // } // else // { // targetItem.StartTracking(); // } // } // //Go through the deleted items and apply them to the new data. // if (source != null) // { // foreach (ITrackableObject sourceItem in source.Where(item => item.IsDeleted())) // { // ITrackableObject targetItem = target.FirstOrDefault(item => item.Id == sourceItem.Id); // if (targetItem != null) // { // targetItem.Delete(); // } // } // } // ////Go through the added items and apply them to the new data. // //if (source != null) // //{ // // foreach (ITrackableObject sourceItem in source.Where(item => item.IsNew())) // // { // // target.Add((TEntity)sourceItem); // // } // //} // return target; //} public static TrackingState MergeTracking(this ITrackableObject target, ITrackableObject source) { TrackingState targetTracker = new TrackingState(target); TrackingState sourceTracker = GetTracker(source); foreach (var property in target.GetType().GetProperties()) { if (property.PropertyType != typeof(TrackingState) && ShouldAllowProperty(property)) { targetTracker.UnmodifiedState.Add(property, property.GetValue(target)); if (property.PropertyType.IsGenericType && property.PropertyType.IsAssignableTo(typeof(System.Collections.IEnumerable))) { dynamic targetList = property.GetValue(target); if (targetList != null) { dynamic sourceList = property.GetValue(source); MergeTracking(targetList, sourceList); } } else if (property.PropertyType.IsAssignableTo(typeof(ITrackableObject))) { ITrackableObject sourceItem = property.GetValue(source) as ITrackableObject; if (sourceItem != null) { if (sourceItem.IsNew() || sourceItem.IsDeleted()) { property.SetValue(target, sourceItem); } else { ITrackableObject trackedItem = property.GetValue(target) as ITrackableObject; if (trackedItem != null) { trackedItem.MergeTracking(sourceItem); } } } } else if (sourceTracker.UnmodifiedState.TryGetValue(property, out object sourceUnmodifiedValue)) { if (IsPropertyModified(source, property, sourceUnmodifiedValue)) { property.SetValue(target, property.GetValue(source)); } } } } trackedObjects[target] = targetTracker; return(targetTracker); }
private static TrackingState StartTracking(ITrackableObject source, TrackingCache cache) { TrackingState tracker = new TrackingState(source); PropertyInfo[] properties; if (!cache.Properties.TryGetValue(source.GetType(), out properties)) { properties = source.GetType().GetProperties(); cache.Properties[source.GetType()] = properties; } foreach (var property in properties) { if (property.PropertyType != typeof(TrackingState) && ShouldAllowProperty(property, cache)) { var value = property.GetValue(source); if (property.PropertyType.IsGenericType && property.PropertyType.IsAssignableTo(typeof(System.Collections.IEnumerable))) { System.Collections.IEnumerable list = (System.Collections.IEnumerable)value; List <ITrackableObject> deletedItems = new List <ITrackableObject>(); foreach (object item in list) { ITrackableObject trackedItem = item as ITrackableObject; if (trackedItem != null) { if (trackedItem.IsTracking() && trackedItem.IsDeleted()) { deletedItems.Add(trackedItem); StopTracking(trackedItem); } else { StartTracking(trackedItem, cache); } } } //Remove any items we detected as having been deleted. IList editableList = list as IList; if (editableList != null) { foreach (var removeItem in deletedItems) { editableList.Remove(removeItem); } } } else if (property.PropertyType.IsAssignableTo(typeof(ITrackableObject))) { ITrackableObject trackedItem = value as ITrackableObject; if (trackedItem != null) { StartTracking(trackedItem, cache); } } tracker.UnmodifiedState.Add(property, value); } } trackedObjects[source] = tracker; return(tracker); }