/// <summary> /// Gets the rows that have differences in the given fields. /// </summary> /// <param name="fieldName">Name of the field.</param> /// <returns> /// Returns a <see cref="IEnumerable{T}" /> representing the rows that have differences. /// </returns> /// <exception cref="System.ArgumentOutOfRangeException"> /// sourceFieldName /// or /// targetFieldName /// </exception> public IEnumerable <IRow> GetRows(string fieldName) { var equailityComparer = new FieldsEqualityComparer(); foreach (var source in this.GetRows(DeltaRowChangeVersion.SourceVersion)) { var s = source.Fields.FindField(fieldName); if (s == -1) { throw new ArgumentOutOfRangeException("fieldName"); } foreach (var target in this.GetRows(DeltaRowChangeVersion.SourceVersion)) { var t = target.Fields.FindField(fieldName); if (t == -1) { throw new ArgumentOutOfRangeException("fieldName"); } if (!equailityComparer.Equals(source, target, s)) { yield return(source); } } } }
/// <summary> /// The main method for resolving conflicts for all of the rows for the <paramref name="conflictClass" /> /// that have the conflict type matching the <paramref name="conflictType" /> enumeration. /// </summary> /// <param name="conflictClass">The class that has the conflicts.</param> /// <param name="currentTable">The table in the current version.</param> /// <param name="preReconcileTable">The table prior to reconciliation.</param> /// <param name="reconcileTable">The table that the current version is reconciling against.</param> /// <param name="commonAncestorTable">The common ancestor table of this version and the reconcile version.</param> /// <param name="conflictType">Type of the conflict.</param> /// <param name="filters">The conflict filters.</param> /// <returns> /// A boolean indicating if all conflicts have been resolved. /// </returns> protected bool ResolveConflicts(IConflictClass conflictClass, ITable currentTable, ITable preReconcileTable, ITable reconcileTable, ITable commonAncestorTable, TableConflictType conflictType, IEnumerable <IConflictFilter> filters) { ISelectionSet set = this.GetConflictSet(conflictClass, conflictType); if (set == null) { return(false); } string tableName = ((IDataset)conflictClass).Name; Log.Info("Resolving the '{0}' type of conflicts for {1} row(s) in the {2} class.", conflictType, set.Count, tableName); var list = filters.Where(o => o.CanResolve(conflictType, conflictClass)).ToArray(); if (list.Length == 0) { Log.Warn("There's no conflict filters available that support the conflict type of {0} for the {1} class.", conflictType, tableName); return(false); } FieldsEqualityComparer equalityComparer = new FieldsEqualityComparer(); List <IConflictRow> rows = new List <IConflictRow>(); IEnumIDs enumIDs = set.IDs; enumIDs.Reset(); int oid; while ((oid = enumIDs.Next()) != -1) { using (ComReleaser cr = new ComReleaser()) { // The row from the edited (current) version. IRow currentRow = currentTable.Fetch(oid); cr.ManageLifetime(currentRow); // The row from the edit (child) version. IRow preReconcileRow = preReconcileTable.Fetch(oid); cr.ManageLifetime(preReconcileRow); // The row from the target (parent) version. IRow reconcileRow = reconcileTable.Fetch(oid); cr.ManageLifetime(reconcileRow); // The row from the common ancestor (as is in the database) version. IRow commonAncestorRow = commonAncestorTable.Fetch(oid); cr.ManageLifetime(commonAncestorRow); // Determine the row conflict type at a granular level. RowConflictType rowConflictType = this.GetRowConflictType(preReconcileRow, reconcileRow, commonAncestorRow, equalityComparer); Log.Info("Resolving the '{0}' conflict type for the {1} row using {2} filter(s).", rowConflictType, oid, list.Length); // Use the filters to "attempt" to resolve the conflicts. IConflictRow conflictRow = new ConflictRow(oid, tableName, rowConflictType); foreach (var filter in list.OrderBy(o => o.Priority)) { conflictRow.Resolution = filter.Resolve(conflictRow, conflictClass, currentRow, preReconcileRow, reconcileRow, commonAncestorRow, this.ChildWins, this.ColumnLevel); } Log.Info("The resolution of the {0} row has been marked as '{1}'.", oid, conflictRow.Resolution); // Save the changes when a resolution was determined. if (conflictRow.Resolution != ConflictResolution.None) { this.SaveAndRebuild(currentRow); } // Add to the list of rows. rows.Add(conflictRow); } } // Add the rows to the extension collection. this.Rows.AddRange(rows); // Remove the OIDs of the conflicts that have been resolved. int[] oids = rows.Where(o => o.Resolution != ConflictResolution.None).Select(o => o.OID).ToArray(); if (this.IsRemovedAfterResolved) { // ESRI states that the RemoveList method on the ISelectionSet should not used from .NET. Instead, call IGeoDatabaseBridge2.RemoveList. set.Remove(oids); } // Output the statistics for the conflicts. int remainder = rows.Count - oids.Length; Log.Info("{0} of the {1} row(s) have been resolved and {2} remain in conflict.", oids.Length, rows.Count, remainder); // Return true when all of the conflicts have been resolved. return(remainder == 0); }