Comparing Projects
Changes to a project's design model can be verified 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.
- The results of comparing projects can be obtained as a difference extraction model
- You can use the difference extraction model to see what changes have been made between projects
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 files (*.nproj)|*.nproj|All files (*.*)|*.*");
if (projectPath == null)
{
/ If canceled, terminate the process
return;
}
/ Specify that the project to compare should not be set as the current project
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);
/ Outputs the number of differences
c.App.Output.WriteLine("Show Diff", $"Number of differences={comparison.Differences.Count}");
}
Project comparison is a two-way comparison. Therefore, if you change the order of projects given to the IDiff.ComputeModels method, the results of the difference extraction will be reversed.
Comparing the entire project cannot be performed if there are unloaded model files. Immediately after opening a project, model files may be in the process of loading in the background, so if you want to compare everything, load the model files beforehand. For details, please refer to Changes in V5.1.
Difference Extraction Model
Next Design compares two projects at the design model identifier level. This comparison result is managed as a difference extraction model.

| Model | Description |
|---|---|
| IDiff | Provides an interface to perform project comparisons and an interface to retrieve the previous comparison result. |
| IModelComparison | A processing unit object that manages the comparison results between any two projects. It holds the comparison results for 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 at the design model level. The Target property allows you to access the model before the change, and the Reference property allows you to access the model after the change. |
| IDifference | This is a difference information object. By referring to this object, you can check the changes in the design model. If extracted as an update difference, you can check the updated field name and the values before and after the update. |
The metamodel structure during comparison is evaluated based on the profile of the modified project. Therefore, if there are changes to the profile between the projects being compared, the differences may not be extracted correctly.
Class Type Field Update and Difference Information
In the update difference information for class type fields, the OldValue property and NewValue property record a list of identifiers of related objects in the field before and after the change. The actual source and destination of the relationship can be traced by identifying the related object from the identifier in the list.
The following is an example of listing newly associated models and models that have been unassociated from the update difference of a class type field.
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 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 difference between the models.
IMatch match = comparison.GetMatch(model);
if (!match.Differences.Any(d => d.IsUpdateItem))
{
return;
}
foreach (IDifference difference in match.Differences)
{
var field = difference.Field;
//Differences in class type fields are recorded in a List of strings
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] {model.Name}'s {field}");
/ Added relation identifier
var addRelationships = afterRelationships.Except(beforeRelationships);
foreach (string relationshipId in addRelationships)
{
/ Get the relationship from the modified project by specifying the 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.");
}
/ Identifier of the deleted relationship
var deleteRelationships = beforeRelationships.Except(afterRelationships);
foreach (string relationshipId in deleteRelationships)
{
/ Get the model and relationship from the original project by specifying the identifier
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} has been removed.");
}
}
}
Diff Information at the Relationship End
In the update diff information extracted from the relationship object, the diff at the relationship end is also notified, in addition to the fields defined in the metamodel. You can check whether the diff information is a diff at the relationship end by examining the IDifference.Field property.
| Field Name | Content |
|---|---|
| @SourceId | Represents the diff of the relationship source. OldValue records the identifier of the relationship source before the change, and NewValue records the identifier of the relationship source after the change. |
| @TargetId | Represents the difference in the associated object. OldValue records the identifier of the associated object before the change, and NewValue records the identifier of the associated object after the change. |
Listing Added Design Models
The following is an example of listing models added in the modified project from the difference extraction model. For added design models, the difference is recorded in the IMatch.Differences property where the IDifference.IsNewItem property is true.
public void GetAddedModels(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);
// List the models where added differences were detected.
var newItemMatches = comparison.Matches.Where(m => m.Differences.Any(d => d.IsNewItem));
foreach (IMatch match in newItemMatches)
{
// The added model is recorded in IMatch.Reference
var model = match.Reference;
if (model is IRelationship relationship)
{
// If it's the result of comparing related objects, you can cast it to IRelationship
c.App.Output.WriteLine("Show Diff", $"[Add]{relationship.Source.Name} and {relationship.Target.Name} are related");
}
else
{
c.App.Output.WriteLine("Show Diff", $"[Add]{model.Name}");
}
}
}
Listing Deleted Design Models
The following is an example of listing models deleted in the modified project from the difference extraction model. Deleted design models are recorded as differences where the IDifference.IsOldItem property is true in the IMatch.Differences property.
public void GetDeletedModels(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);
//List the models for which deletion differences were detected.
var oldItemMatches = comparison.Matches.Where(m => m.Differences.Any(d => d.IsOldItem));
foreach (IMatch match in oldItemMatches)
{
//Deleted models are recorded in IMatch.Target
var model = match.Target;
if (model is IRelationship relationship)
{
//If it's the result of comparing related objects, you can cast it to IRelationship
c.App.Output.WriteLine("Show Diff", $"[Delete]{relationship.Source.Name} and {relationship.Target.Name} are related");
}
else
{
c.App.Output.WriteLine("Show Diff", $"[Delete]{model.Name}");
}
}
}
Deleted models do not exist in the modified project and therefore cannot be retrieved from the modified project. The IModelComparison.BeforeProject property can be used to access the project before the modification.
Listing Updated Design Models
The following is an example of listing models updated in the modified project from the difference extraction model. For deleted design models, the IMatch.Differences property records a difference where the IDifference.IsUpdateItem property is 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 the 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's the result of comparing related objects, you can cast it to IRelationship
c.App.Output.WriteLine("Show Diff", $"[Updated] Relationship between {relationship.Source.Name} and {relationship.Target.Name}");
}
else
{
c.App.Output.WriteLine("Show Diff", $"[Updated] {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}");
}
}
}
Listing Moved Design Models
The following is an example of listing the models moved in the modified project from the difference extraction model. Model movement is obtained from the difference information of related objects.
In V2.0, differences when a model is moved between the projects before and after comparison are not extracted in the moved model. Please note that this cannot be evaluated using the IDifference.IsMoveItem property.
public void GetMovedModels(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 related models for which update differences were detected.
var updateRelationshipMatches = comparison.Matches.Where(m => m.Target is IRelationship && m.Differences.Any(d => d.IsUpdateItem));
foreach (IMatch match in updateRelationshipMatches)
{
/ The updated related model is recorded in IMatch.Target
var relationship = (IRelationship)match.Target;
if (!relationship.IsEmbedded)
{
/ Skip if it's 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 source relationship
continue;
}
/ The moved model can be obtained in the related target relationship
var model = relationship.Target;
/ The owner after the move can be obtained from the related source of the relationship.
var newParent = relationship.Source;
/ The owner before the move can be obtained from the related source of the relationship 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}");
}
}
Detecting the Move of a Design Model from Difference Information
When evaluating whether a model has been moved, based on the design model, you can detect this from the difference information of the related object with the owner, which can be obtained using IModel.GetOwnerRelationship(). If there is an update difference in the @SourceId field in the difference of the related object with the owner, it means that the owner of the design model has 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 difference in ownership relationships.
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 ownership 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 owner after the move can be obtained from the source of the relationship
var newRelationship = (IRelationship)match.Target;
var newParent = newRelationship.Source;
/ The previous owner can be retrieved from the previous relationship's source.
var oldRelationship = (IRelationship)match.Reference;
var oldParent = oldRelationship.Source;
c.App.Output.WriteLine("Show Diff", $"{model.Name} has been moved from {oldParent.Name} to {newParent.Name}.");
}