Skip to main content

Compare Projects

You can check the changes in the design model of a project by comparing the project before and after the changes and evaluating the comparison results. To compare the project before and after the changes, use the ComputeModels method of the IDiff object.

public void ComputeProjects(ICommandContext c, ICommandParams p) 
{
//Open the project to compare with the current project
var projectPath = c.App.Window.UI.ShowOpenFileDialog("Open project to compare", "Project file (*.nproj)|*.nproj|All files (*.*)|*.*");
if (projectPath == null)
{
//If canceled, the process will end
return;
}
//Specify not to set the project to compare as the current one
var diffProject = c.App.Workspace.OpenProject(projectPath, false);

//Compare the projects
var project = c.App.Workspace.CurrentProject;
IModelComparison comparison = c.App.Diff.ComputeModels(project, diffProject);

//Output the number of extracted differences
c.App.Output.WriteLine("Show Diff", $"Number of extracted differences = {comparison.Differences.Count}");
}
note

Project comparison is a two-way comparison. Therefore, if you switch the order of projects given to the IDiff.ComputeModels method, the result of the difference extraction will be reversed.

Difference extraction model

Next Design compares the two projects to be compared by design model identifier. The comparison result is managed as a difference extraction model.

Difference Extraction Model

|Model|Description|
|:---|:---|
|IDiff|Provides an interface for executing project comparisons and for obtaining the results of previous comparisons. |
|IModelComparison|A processing unit object that manages the comparison results between any projects. It holds the comparison results of all design models. You can access the project before the change with the BeforeProject property, and the project after the change with the AfterProject property. |
|IMatch|A comparison result object for each design model. You can access the model before the change with the Target property, and the model after the change with the Reference property. |
|IDifference|A difference information object. You can check the changes to the design model by referring to this object. If extracted as an update difference, you can check the updated field name and the values ​​before and after the update. |

info

When performing a comparison, the metamodel structure is evaluated based on the profile of the project after the change. Therefore, if there are changes to the profile between the projects being compared, the differences may not be extracted correctly.

Updates and difference information for class type fields
In the update difference information for class type fields, the OldValue property and the NewValue property record a list of identifiers of related objects in the field before and after the change, respectively. The actual related source and related destination can be traced by identifying the related objects from the identifiers in the list.

The following is an example of a list of newly related models and models that have been removed from the update difference of a class type field.

public void CheckModelMoved(ICommandContext c, ICommandParams p) 
{
//Get the comparison result of the current project
var project = c.App.Workspace.CurrentProject;
IModelComparison comparison = c.App.Diff.GetComparison(project);

//Get the project before the change
var beforeProject = comparison.BeforeProject;

//Get the ownership relationship with the owner of the selected model
var model = c.App.Workspace.CurrentModel;

//Get the model difference.
IMatch match = comparison.GetMatch(model);

if (!match.Differences.Any(d => d.IsUpdateItem))
{
return;
}

foreach (IDifference difference in match.Differences)
{
var field = difference.Field;
//Differences for class-type fields are recorded in a string List
var beforeRelationships = difference.OldValue as IList<string>;
var afterRelationships = difference.NewValue as IList<string>;
if (beforeRelationships == null || afterRelationships == null)
{
continue;
}

c.App.Output.WriteLine("Show Diff", $"[Updated]{field} of {model.Name}");

//Identifiers of added relationships
var addRelationships = afterRelationships.Except(beforeRelationships);
foreach (string relationshipId in addRelationships)
{
//Get the relationship from the changed project by specifying its identifier
IRelationship relationship = project.GetRelationshipById(relationshipId);
//Get the other model from the relationship
IModel related = model.Equals(relationship.Source) ? relationship.Target : relationship.Source;
c.App.Output.WriteLine("Show Diff", $"A relationship with {related.Name} has been added. ");
}

//Identifiers of deleted relationships
var deleteRelationships = beforeRelationships.Except(afterRelationships);
foreach (string relationshipId in deleteRelationships)
{
//Get models and relationships from the old project by their identifiers
IModel beforeModel = beforeProject.GetModelById(model.Id);
IRelationship relationship = beforeProject.GetRelationshipById(relationshipId);
//Get the other model from the relationship
IModel related = beforeModel.Equals(relationship.Source) ? relationship.Target : relationship.Source;
c.App.Output.WriteLine("Show Diff", $"The relationship with {related.Name} was deleted.");
}
}
}

Difference information of the association end
In the update difference information extracted from the association object, the difference of the association end is notified in addition to the fields defined in the meta model. You can check whether the difference information is a difference of the association end by checking the IDifference.Field property.

|Field Name|Contents|
|:---|:---|
|@SourceId|Indicates the difference of the association source. The identifier of the association source before the change is recorded in OldValue, and the identifier of the association source after the change is recorded in NewValue. |
|@TargetId|Indicates the difference of the association destination. The identifier of the association destination before the change is recorded in OldValue, and the identifier of the association destination after the change is recorded in NewValue. |

List added design models

The following is an example of listing the models added in the project after the change from the difference extraction model. For added design models, the IMatch.Differences property records differences where the IDifference.IsNewItem property is true.

public void GetAddedModels(ICommandContext c, ICommandParams p) 
{
//Get the comparison results for the current project
var project = c.App.Workspace.CurrentProject;
IModelComparison comparison = c.App.Diff.GetComparison(project);

//List the models for which additional differences were detected.
var newItemMatches = comparison.Matches.Where(m => m.Differences.Any(d => d.IsNewItem));
foreach (IMatch match in newItemMatches)
{
//The model you added is recorded in IMatch.Reference
var model = match.Reference;
if (model is IRelationship relationship)
{
//If it's a comparison result of related objects, you can cast it to IRelationship
c.App.Output.WriteLine("Show Diff", $"[Add]{relationship.Source.Name} and {relationship.Target.Name}");
}
else
{
c.App.Output.WriteLine("Show Diff", $"[Add]{model.Name}");
}
}
}

Listing deleted design models

The following is an example of listing models deleted in a changed project from a difference extraction model. For deleted design models, the IMatch.Differences property records differences where the IDifference.IsOldItem property is true.

public void GetDeletedModels(ICommandContext c, ICommandParams p) 
{
//Get the comparison results for the current project
var project = c.App.Workspace.CurrentProject;
IModelComparison comparison = c.App.Diff.GetComparison(project);

//List models for which deletion differences were detected.
var oldItemMatches = comparison.Matches.Where(m => m.Differences.Any(d => d.IsOldItem));
foreach (IMatch match in oldItemMatches)
{
//The deleted model is recorded in IMatch.Target
var model = match.Target;
if (model is IRelationship relationship)
{
//If it is a comparison result of related objects, it can be cast to IRelationship
c.App.Output.WriteLine("Show Diff", $"[Delete]{relationship.Source.Name} and {relationship.Target.Name}");
}
else
{
c.App.Output.WriteLine("Show Diff", $"[Delete]{model.Name}");
}
}
}
tip

Deleted models do not exist in the changed project, so they cannot be retrieved from the changed project. You can access the project before the change with the IModelComparison.BeforeProject property.

List updated design models

The following is an example of listing models updated in the changed project from the difference extraction model. For deleted design models, the IMatch.Differences property records differences with the IDifference.IsUpdateItem property set to true.

public void GetUpdateModels(ICommandContext c, ICommandParams p) 
{
//Get the comparison results for the current project
var project = c.App.Workspace.CurrentProject;
IModelComparison comparison = c.App.Diff.GetComparison(project);

//List models for which update differences were detected.
var updateItemMatches = comparison.Matches.Where(m => m.Differences.Any(d => d.IsUpdateItem));
foreach (IMatch match in updateItemMatches)
{
//The updated model is recorded in IMatch.Target
var model = match.Target;
if (model is IRelationship relationship)
{
//If it is a comparison result of related objects, it can be cast to IRelationship
c.App.Output.WriteLine("Show Diff", $"[Update]Relationship between {relationship.Source.Name} and {relationship.Target.Name}");
}
else
{
c.App.Output.WriteLine("Show Diff", $"[Update]{model.Name}");
}

//Output the differences for each field
var differences = match.Differences.Where(d => d.IsUpdateItem);
foreach (IDifference difference in differences)
{
var field = difference.Field;
var oldValue = difference.OldValue;
var newValue = difference.NewValue;
if (oldValue is IList<string> oldValues ​​&& newValue is IList<string> newValues)
{
c.App.Output.WriteLine("Show Diff", $" - {field}:{oldValues.Count} -> {newValues.Count}");
continue;
}
c.App.Output.WriteLine("Show Diff", $" - {field}:{oldValue} -> {newValue}");
}
}
}

List the moved design models

The following is an example of listing the models moved in the changed project from the difference extraction model. Model movement is obtained from the difference information of related objects.

Differences for model movement

In V2.0, if a model is moved between projects before and after comparison, the difference is not extracted in the moved model. Please note that it cannot be evaluated using the IDifference.IsMoveItem property.

public void GetMovedModels(ICommandContext c, ICommandParams p) 
{
//Get the comparison result of the current project
var project = c.App.Workspace.CurrentProject;
IModelComparison comparison = c.App.Diff.GetComparison(project);

//Get the related model where an update difference was detected.
var updateRelationshipMatches = comparison.Matches.Where(m => m.Target is IRelationship && m.Differences.Any(d => d.IsUpdateItem));
foreach (IMatch match in updateRelationshipMatches)
{
//The related model after the update is recorded in IMatch.Target
var relationship = (IRelationship)match.Target;
if (!relationship.IsEmbedded)
{
//Skip if not an owned relationship
continue;
}
var difference = match.Differences.FirstOrDefault(d => d.Field == "@SourceId");
if (difference == null)
{
//Skip if there is no difference in the related source
continue;
}
//The moved model can be obtained from the related destination of the relationship
var model = relationship.Target;
//The owner after the move can be obtained from the relationship's source
var newParent = relationship.Source;
//The owner before the move can be obtained from the relationship's source before the change
var oldRelationship = (IRelationship)match.Reference;
var oldParent = oldRelationship.Source;

c.App.Output.WriteLine("Show Diff", $"[Move]{model.Name}:{oldParent.Name} ==> {newParent.Name}");
}
}

Detect the move of the design model from the difference information

When evaluating whether a model has been moved based on the design model, it can be detected from the difference information of the related object with the owner, which can be obtained with IModel.GetOwnerRelationship(). If there is an update difference in the @SourceId field in the difference between the related object with the owner, the owner of the design model has been changed.

public void CheckModelMoved(ICommandContext c, ICommandParams p) 
{
//Get the comparison result for the current project
var project = c.App.Workspace.CurrentProject;
IModelComparison comparison = c.App.Diff.GetComparison(project);

//Get the ownership relationship with the owner of the selected model
var model = c.App.Workspace.CurrentModel;
var ownerRelationship = model.GetOwnerRelationship();

//Get the ownership relationship difference.
IMatch match = comparison.GetMatch(ownerRelationship);

if (!match.HasDifference)
{
c.App.Output.WriteLine("Show Diff", $"{model.Name} has not been moved.");
return;
}

//Get the difference of the source of the owned relationship.
var difference = match.Differences.FirstOrDefault(d => d.IsUpdateItem && d.Field == "@SourceId");
if (difference == null)
{
c.App.Output.WriteLine("Show Diff", $"{model.Name} has not been moved.");
return;
}

//The source of the owner after the move can be obtained from the source of the relationship.
var newRelationship = (IRelationship)match.Target;
var newParent = newRelationship.Source;
//The owner before the move can be obtained from the source of the relationship before the change.
var oldRelationship = (IRelationship)match.Reference;
var oldParent = oldRelationship.Source;
c.App.Output.WriteLine("Show Diff", $"{model.Name} was moved from {oldParent.Name} to {newParent.Name}.");
}