/// <summary> /// Gets the type of the dependency root object for the specified property. /// </summary> /// <param name="difference">The difference.</param> /// <param name="accessor">The property accessor.</param> /// <returns>The type of the dependency root object for the specified property; /// <see langword="null" />, if none.</returns> /// <remarks> /// Returns <paramref name="accessor"/>.<see cref="PropertyAccessor.DependencyRootType"/> /// by default. /// </remarks> protected virtual Type GetDependencyRootType(Difference difference, PropertyAccessor accessor) { return(accessor.DependencyRootType); }
/// <summary> /// Determines whether specified property is mutable. /// </summary> /// <param name="difference">The difference.</param> /// <param name="accessor">The property accessor.</param> /// <returns><see langword="true"/> if th specified property is mutable; /// otherwise, <see langword="false"/>. /// </returns> /// <remarks> /// Returns <paramref name="accessor"/>.<see cref="PropertyAccessor.IsVolatile"/> /// by default. /// </remarks> protected virtual bool IsVolatile(Difference difference, PropertyAccessor accessor) { return(accessor.IsVolatile); }
/// <summary> /// Visits the unknown difference. /// </summary> /// <param name="difference">The difference.</param> /// <returns> /// A sequence of actions that must be performed to upgrade /// from <see cref="IDifference.Source"/> of the specified /// difference to its <see cref="IDifference.Target"/>. /// </returns> /// <exception cref="NotSupportedException">Always thrown by this method.</exception> protected virtual void VisitUnknownDifference(Difference difference) { throw new NotSupportedException(); }
/// <inheritdoc/> /// <exception cref="ArgumentOutOfRangeException"><c>hints.SourceModel</c> or <c>hints.TargetModel</c> /// is out of range.</exception> /// <exception cref="InvalidOperationException">Upgrade sequence validation has failed.</exception> public ReadOnlyList <NodeAction> GetUpgradeSequence(Difference difference, HintSet hints, IComparer comparer) { ArgumentValidator.EnsureArgumentNotNull(hints, "hints"); ArgumentValidator.EnsureArgumentNotNull(comparer, "comparer"); if (difference == null) { return(new ReadOnlyList <NodeAction>(Enumerable.Empty <NodeAction>().ToList())); } TemporaryRenames = new Dictionary <string, Node>(StringComparer.OrdinalIgnoreCase); SourceModel = (IModel)difference.Source; TargetModel = (IModel)difference.Target; Hints = hints ?? new HintSet(SourceModel, TargetModel); Comparer = comparer; if (Hints.SourceModel != SourceModel) { throw new ArgumentOutOfRangeException("hints.SourceModel"); } if (Hints.TargetModel != TargetModel) { throw new ArgumentOutOfRangeException("hints.TargetModel"); } CurrentModel = (IModel)SourceModel.Clone(null, SourceModel.Name); Difference = difference; var previous = currentAsync.Value; currentAsync.Value = this; using (NullActionHandler.Instance.Activate()) { try { var actions = new GroupingNodeAction(); ProcessStage(UpgradeStage.CleanupData, actions); ProcessStage(UpgradeStage.Prepare, actions); ProcessStage(UpgradeStage.TemporaryRename, actions); ProcessStage(UpgradeStage.Upgrade, actions); ProcessStage(UpgradeStage.CopyData, actions); ProcessStage(UpgradeStage.PostCopyData, actions); ProcessStage(UpgradeStage.Cleanup, actions); var validationHints = new HintSet(CurrentModel, TargetModel); Hints.OfType <IgnoreHint>().ForEach(validationHints.Add); var diff = comparer.Compare(CurrentModel, TargetModel, validationHints); if (diff != null) { CoreLog.InfoRegion(Strings.LogAutomaticUpgradeSequenceValidation); CoreLog.Info(Strings.LogValidationFailed); CoreLog.Info(Strings.LogItemFormat, Strings.Difference); CoreLog.Info("{0}", diff); CoreLog.Info(Strings.LogItemFormat + "\r\n{1}", Strings.UpgradeSequence, new ActionSequence() { actions }); CoreLog.Info(Strings.LogItemFormat, Strings.ExpectedTargetModel); TargetModel.Dump(); CoreLog.Info(Strings.LogItemFormat, Strings.ActualTargetModel); CurrentModel.Dump(); throw new InvalidOperationException(Strings.ExUpgradeSequenceValidationFailure); } return(new ReadOnlyList <NodeAction>(actions.Actions, true)); } finally { currentAsync.Value = previous; } } }
/// <inheritdoc/> /// <exception cref="ArgumentOutOfRangeException"><c>hints.SourceModel</c> or <c>hints.TargetModel</c> /// is out of range.</exception> public ReadOnlyList <NodeAction> GetUpgradeSequence(Difference difference, HintSet hints) { return(GetUpgradeSequence(difference, hints, new Comparer())); }
/// <summary> /// Compares source and target node properties. /// </summary> /// <param name="source">The source.</param> /// <param name="target">The target.</param> /// <param name="difference">The difference.</param> protected virtual void CompareProperties(Node source, Node target, NodeDifference difference) { var any = source ?? target; foreach (var pair in any.PropertyAccessors) { var accessor = pair.Value; if (accessor.IgnoreInComparison) { continue; } var property = accessor.PropertyInfo; using (CreateContext().Activate()) { Context.PropertyAccessor = accessor; object sourceValue = (source == null || !accessor.HasGetter) ? accessor.Default : accessor.Getter.Invoke(source); object targetValue = (target == null || !accessor.HasGetter) ? accessor.Default : accessor.Getter.Invoke(target); object anyValue = sourceValue ?? targetValue; if (anyValue == null) { continue; // Both are null } Difference propertyDifference = null; if (!IsReference(sourceValue, targetValue)) { propertyDifference = Visit(sourceValue, targetValue); } else if (Stage == ComparisonStage.ReferenceComparison) { if (IsIgnored(sourceValue)) { difference.MovementInfo = 0; } else { propertyDifference = GetReferencedPropertyDifference(sourceValue, targetValue, target, property.Name); } } if (propertyDifference == null) { continue; } if (any.Nesting.PropertyInfo != null && accessor.DependencyRootType == any.Nesting.PropertyInfo.PropertyType) { if (propertyDifference is NodeDifference) { ((NodeDifference)propertyDifference).IsDependentOnParent = true; } else if (propertyDifference is NodeCollectionDifference) { ((NodeCollectionDifference)propertyDifference).ItemChanges .ForEach(item => item.IsDependentOnParent = true); } } difference.PropertyChanges.Add(property.Name, propertyDifference); } } }