in BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/Comparison.cs [642:997]
public override void ValidateSelection()
{
#region Refresh/reconnect source and target dbs to check if server definition has changed
bool reconnect = false;
try
{
if (!_sourceTabularModel.ConnectionInfo.UseBimFile) _sourceTabularModel.TomDatabase.Refresh();
if (!_targetTabularModel.ConnectionInfo.UseBimFile) _targetTabularModel.TomDatabase.Refresh();
}
catch (Exception)
{
reconnect = true;
}
if (reconnect || _uncommitedChanges)
{
// Reconnect to re-initialize
_sourceTabularModel = new TabularModel(this, _comparisonInfo.ConnectionInfoSource, _comparisonInfo);
_sourceTabularModel.Connect();
_targetTabularModel = new TabularModel(this, _comparisonInfo.ConnectionInfoTarget, _comparisonInfo);
_targetTabularModel.Connect();
}
if (!_sourceTabularModel.ConnectionInfo.UseProject && _sourceTabularModel.TomDatabase.LastSchemaUpdate > _lastSourceSchemaUpdate)
{
throw new Exception("The definition of the source database has changed since the comparison was run. Please re-run the comparison.");
}
if (!_targetTabularModel.ConnectionInfo.UseProject && _targetTabularModel.TomDatabase.LastSchemaUpdate > _lastTargetSchemaUpdate)
{
throw new Exception("The definition of the target database has changed since the comparison was run. Please re-run the comparison.");
}
_uncommitedChanges = true;
#endregion
#region Iterate of objects for delete/create/updates
#region Backup perspectives, cultures and roles
/*It's easier to take a backup of perspectives, cultures and roles now and add back after table changes, rather than every
time update a table, take a temp backup to add back columns/measures. Also would need to remove deleted tables/meausures, ...
Gets pretty hairy.
*/
_targetTabularModel.BackupAffectedObjects();
#endregion
#region DataSources
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
DeleteDataSource(comparisonObject);
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
CreateDataSource(comparisonObject);
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
UpdateDataSource(comparisonObject);
}
#endregion
#region Expressions
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
DeleteExpression(comparisonObject);
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
CreateExpression(comparisonObject);
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
UpdateExpression(comparisonObject);
}
#endregion
#region Model1
//Doing before tables in case need to set DiscourageImplicitMeasures=true to create calc groups downstream
bool updatedModel = false;
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (UpdateModel(comparisonObject, true))
{
updatedModel = true;
break;
}
}
#endregion
#region Tables
// do deletions first to minimize chance of conflict
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
DeleteTable(comparisonObject);
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
CreateTable(comparisonObject);
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
UpdateTable(comparisonObject);
}
#endregion
#region Relationships
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
DeleteRelationship(childComparisonObject); //Relationship
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
CreateRelationship(childComparisonObject, comparisonObject.SourceObjectName); //Relationship, Table
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
UpdateRelationship(childComparisonObject, comparisonObject.SourceObjectName); //Relationship, Table
}
}
_targetTabularModel.ValidateRelationships();
#endregion
_targetTabularModel.CleanUpVariations();
#region Model2
//Doing model after tables in case there are calc group tables created so cannot set DisableImplictMeasures=false
if (!updatedModel)
{
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (UpdateModel(comparisonObject, false))
break;
}
}
#endregion
#region Measures / KPIs
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
DeleteMeasure(childComparisonObject); //Measure
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
CreateMeasure(childComparisonObject, comparisonObject.SourceObjectName); //Measure, Table
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
UpdateMeasure(childComparisonObject, comparisonObject.SourceObjectName); //Measure, Table
}
}
#endregion
#region CalculationItems
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
DeleteCalculationItem(childComparisonObject, comparisonObject.SourceObjectName); //CalculationItem, Table
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
CreateCalculationItem(childComparisonObject, comparisonObject.SourceObjectName); //CalculationItem, Table
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
foreach (ComparisonObject childComparisonObject in comparisonObject.ChildComparisonObjects)
{
UpdateCalculationItem(childComparisonObject, comparisonObject.SourceObjectName); //CalculationItem, Table
}
}
#endregion
#region Perspectives
//Restore perspectives that were backed up earlier. Having done this there won't be any dependency issues, so can start comparison changes.
_targetTabularModel.RestorePerspectives();
// Do separate loops of _comparisonObjectects for Delete, Create, Update to ensure informational logging order is consistent with other object types. This also ensures deletions are done first to minimize chance of conflict.
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Perspective && comparisonObject.MergeAction == MergeAction.Delete)
{
_targetTabularModel.DeletePerspective(comparisonObject.TargetObjectInternalName);
OnValidationMessage(new ValidationMessageEventArgs($"Delete perspective [{comparisonObject.TargetObjectName}].", ValidationMessageType.Perspective, ValidationMessageStatus.Informational));
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Perspective && comparisonObject.MergeAction == MergeAction.Create)
{
_targetTabularModel.CreatePerspective(_sourceTabularModel.Perspectives.FindById(comparisonObject.SourceObjectInternalName).TomPerspective);
OnValidationMessage(new ValidationMessageEventArgs($"Create perspective [{comparisonObject.SourceObjectName}].", ValidationMessageType.Perspective, ValidationMessageStatus.Informational));
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Perspective && comparisonObject.MergeAction == MergeAction.Update)
{
_targetTabularModel.UpdatePerspective(_sourceTabularModel.Perspectives.FindById(comparisonObject.SourceObjectInternalName).TomPerspective, _targetTabularModel.Perspectives.FindById(comparisonObject.TargetObjectInternalName).TomPerspective);
OnValidationMessage(new ValidationMessageEventArgs($"Update perspective [{comparisonObject.TargetObjectName}].", ValidationMessageType.Perspective, ValidationMessageStatus.Informational));
}
}
#endregion
#region Roles
//Restore roles that were backed up earlier. Having done this there won't be any dependency issues, so can start comparison changes.
_targetTabularModel.RestoreRoles();
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Role && comparisonObject.MergeAction == MergeAction.Delete)
{
if (DesktopHardened(comparisonObject, ValidationMessageType.Role))
{
_targetTabularModel.DeleteRole(comparisonObject.TargetObjectInternalName);
OnValidationMessage(new ValidationMessageEventArgs($"Delete role [{comparisonObject.TargetObjectName}].", ValidationMessageType.Role, ValidationMessageStatus.Informational));
}
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Role && comparisonObject.MergeAction == MergeAction.Create)
{
if (DesktopHardened(comparisonObject, ValidationMessageType.Role))
{
_targetTabularModel.CreateRole(_sourceTabularModel.Roles.FindById(comparisonObject.SourceObjectInternalName).TomRole);
OnValidationMessage(new ValidationMessageEventArgs($"Create role [{comparisonObject.SourceObjectName}].", ValidationMessageType.Role, ValidationMessageStatus.Informational));
}
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Role && comparisonObject.MergeAction == MergeAction.Update)
{
if (DesktopHardened(comparisonObject, ValidationMessageType.Role))
{
_targetTabularModel.UpdateRole(_sourceTabularModel.Roles.FindById(comparisonObject.SourceObjectInternalName), _targetTabularModel.Roles.FindById(comparisonObject.TargetObjectInternalName));
OnValidationMessage(new ValidationMessageEventArgs($"Update role [{comparisonObject.TargetObjectName}].", ValidationMessageType.Role, ValidationMessageStatus.Informational));
}
}
}
_targetTabularModel.RolesCleanup();
#endregion
_targetTabularModel.CleanUpAggregations();
#region Cultures
//Restore cultures that were backed up earlier. Having done this there won't be any dependency issues, so can start comparison changes.
//Note that cannot restore cultures before finished perspective comparison changes above, because cultures can have dependencies on perspectives.
_targetTabularModel.RestoreCultues();
// Do separate loops of _comparisonObjectects for Delete, Create, Update to ensure informational logging order is consistent with other object types. This also ensures deletions are done first to minimize chance of conflict.
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Culture && comparisonObject.MergeAction == MergeAction.Delete)
{
_targetTabularModel.DeleteCulture(comparisonObject.TargetObjectInternalName);
OnValidationMessage(new ValidationMessageEventArgs($"Delete culture [{comparisonObject.TargetObjectName}].", ValidationMessageType.Culture, ValidationMessageStatus.Informational));
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Culture && comparisonObject.MergeAction == MergeAction.Create)
{
_targetTabularModel.CreateCulture(_sourceTabularModel.Cultures.FindById(comparisonObject.SourceObjectInternalName).TomCulture);
OnValidationMessage(new ValidationMessageEventArgs($"Create culture [{comparisonObject.SourceObjectName}].", ValidationMessageType.Culture, ValidationMessageStatus.Informational));
}
}
foreach (ComparisonObject comparisonObject in _comparisonObjects)
{
if (comparisonObject.ComparisonObjectType == ComparisonObjectType.Culture && comparisonObject.MergeAction == MergeAction.Update)
{
_targetTabularModel.UpdateCulture(_sourceTabularModel.Cultures.FindById(comparisonObject.SourceObjectInternalName).TomCulture, _targetTabularModel.Cultures.FindById(comparisonObject.TargetObjectInternalName).TomCulture);
OnValidationMessage(new ValidationMessageEventArgs($"Update culture [{comparisonObject.TargetObjectName}].", ValidationMessageType.Culture, ValidationMessageStatus.Informational));
}
}
#endregion
#endregion
#region Missing measure dependencies
if (_comparisonInfo.OptionsInfo.OptionMeasureDependencies)
{
foreach (Table table in _targetTabularModel.Tables)
{
foreach (Measure measure in table.Measures)
{
foreach (string missingDependency in measure.FindMissingMeasureDependencies())
{
OnValidationMessage(new ValidationMessageEventArgs($"Measure [{measure.InternalName}] in table '{table.Name}' contains dependency on measure/column [{missingDependency}], which (considering changes to target) cannot be found in target model.", ValidationMessageType.MeasureCalculationDependency, ValidationMessageStatus.Informational));
}
}
}
}
#endregion
OnResizeValidationHeaders(new EventArgs());
}