/// <summary> /// Recursively enable or disable tracking on trackable entities in an object graph. /// </summary> /// <param name="item">Trackable object</param> /// <param name="enableTracking">Enable or disable change-tracking</param> /// <param name="visitationHelper">Circular reference checking helper</param> /// <param name="oneToManyOnly">True if tracking should be set only for OneToMany relations</param> public static void SetTracking(this ITrackable item, bool enableTracking, ObjectVisitationHelper visitationHelper = null, bool oneToManyOnly = false) { // Iterator entity properties foreach (var navProp in item.GetNavigationProperties()) { // Skip if 1-M only if (!oneToManyOnly) { // Set tracking on 1-1 and M-1 properties foreach (var refProp in navProp.AsReferenceProperty()) { // Get ref prop change tracker ITrackingCollection refChangeTracker = item.GetRefPropertyChangeTracker(refProp.Property.Name); if (refChangeTracker != null) { // Set tracking on ref prop change tracker refChangeTracker.SetTracking(enableTracking, visitationHelper, oneToManyOnly); } } } // Set tracking on 1-M and M-M properties (if not 1-M only) foreach (var colProp in navProp.AsCollectionProperty <ITrackingCollection>()) { bool isOneToMany = !IsManyToManyChildCollection(colProp.EntityCollection); if (!oneToManyOnly || isOneToMany) { colProp.EntityCollection.SetTracking(enableTracking, visitationHelper, oneToManyOnly); } } } }
/// <summary> /// Recursively enable or disable tracking on trackable entities in an object graph. /// </summary> /// <param name="item">Trackable object</param> /// <param name="enableTracking">Enable or disable change-tracking</param> /// <param name="visitationHelper">Circular reference checking helper</param> public static void SetTracking(this ITrackable item, bool enableTracking, ObjectVisitationHelper visitationHelper = null) { // Iterator entity properties foreach (var navProp in item.GetNavigationProperties()) { // Set tracking on 1-1 and M-1 properties foreach (var refProp in navProp.AsReferenceProperty()) { // Get ref prop change tracker ITrackingCollection refChangeTracker = item.GetRefPropertyChangeTracker(refProp.Property.Name); if (refChangeTracker != null) { // Set tracking on ref prop change tracker refChangeTracker.SetTracking(enableTracking, visitationHelper); } } // Set tracking on 1-M and M-M properties foreach (var colProp in navProp.AsCollectionProperty <ITrackingCollection>()) { colProp.EntityCollection.SetTracking(enableTracking, visitationHelper); } } }
/// <summary> /// Get entities that have been added, modified or deleted, including trackable /// reference and child entities. /// </summary> /// <param name="items">Collection of ITrackable objects</param> /// <returns>Collection containing only added, modified or deleted entities</returns> private IEnumerable <ITrackable> GetChanges(IEnumerable <ITrackable> items) { // Prevent endless recursion by collection if (!visitationHelper.TryVisit(items)) { yield break; } // Prevent endless recursion by item items = items.Where(i => visitationHelper.TryVisit(i)).ToList(); // Iterate items in change-tracking collection foreach (ITrackable item in items) { // Downstream changes flag bool hasDownstreamChanges = false; // Iterate entity properties foreach (var navProp in item.GetNavigationProperties()) { // Process 1-1 and M-1 properties foreach (var refProp in navProp.AsReferenceProperty()) { ITrackable trackableRef = refProp.EntityReference; // if already visited and unchanged, set to null if (visitationHelper.IsVisited(trackableRef)) { if ((trackableRef.TrackingState == TrackingState.Unchanged || trackableRef.TrackingState == TrackingState.Deleted)) { EntityInfo(item).RefNavPropUnchanged.Add(refProp.Property); } continue; } // Get changed ref prop ITrackingCollection refChangeTracker = trackableRef.GetRefPropertyChangeTracker(refProp.Property.Name);//item.GetRefPropertyChangeTracker(refProp.Property.Name); if (refChangeTracker != null) { hasDownstreamChanges = HasDownstreamChanges(refChangeTracker, trackableRef, item, refProp, hasDownstreamChanges); } } // Process 1-M and M-M properties foreach (var colProp in navProp.AsCollectionProperty <IList>()) { // Get changes on child collection var trackingItems = colProp.EntityCollection; if (trackingItems.Count > 0) { // Continue recursion if trackable hasn't been visited if (!visitationHelper.IsVisited(trackingItems)) { hasDownstreamChanges = GetChangesOnChildCollection(trackingItems, hasDownstreamChanges, item, colProp); } } } } // Return item if it has changes if (hasDownstreamChanges || item.TrackingState != TrackingState.Unchanged) { yield return(item); } } }