diff --git a/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs b/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs
index 8efd75d..f2d083b 100644
--- a/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs
+++ b/BismNormalizer/BismNormalizer.CommandLine/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("4.0.0.16")]
-[assembly: AssemblyFileVersion("4.0.0.16")]
+[assembly: AssemblyVersion("4.0.0.18")]
+[assembly: AssemblyFileVersion("4.0.0.18")]
diff --git a/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs b/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs
index fc46226..86f1e06 100644
--- a/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs
+++ b/BismNormalizer/BismNormalizer.IconSetup/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("4.0.0.16")]
-[assembly: AssemblyFileVersion("4.0.0.16")]
+[assembly: AssemblyVersion("4.0.0.18")]
+[assembly: AssemblyFileVersion("4.0.0.18")]
diff --git a/BismNormalizer/BismNormalizer/BismNormalizer.csproj b/BismNormalizer/BismNormalizer/BismNormalizer.csproj
index 8c0a239..9291238 100644
--- a/BismNormalizer/BismNormalizer/BismNormalizer.csproj
+++ b/BismNormalizer/BismNormalizer/BismNormalizer.csproj
@@ -287,7 +287,7 @@
-
+
diff --git a/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs b/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs
index 5933a0b..2681011 100644
--- a/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs
+++ b/BismNormalizer/BismNormalizer/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("4.0.0.16")]
-[assembly: AssemblyFileVersion("4.0.0.16")]
+[assembly: AssemblyVersion("4.0.0.18")]
+[assembly: AssemblyFileVersion("4.0.0.18")]
diff --git a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipChain.cs b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipChainsFromRoot.cs
similarity index 74%
rename from BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipChain.cs
rename to BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipChainsFromRoot.cs
index 90a23be..439364c 100644
--- a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipChain.cs
+++ b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipChainsFromRoot.cs
@@ -7,7 +7,7 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
///
/// Represents a chain of RelationshipLink objects, used to detect ambiguity in relationship paths.
///
- public class RelationshipChain : List
+ public class RelationshipChainsFromRoot : List
{
///
/// Find end table by name.
@@ -49,9 +49,26 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
/// Boolean indicating if the end table was found.
public bool ContainsEndTableName(string endTableName)
{
- foreach (RelationshipLink ReferencedTable in this)
+ foreach (RelationshipLink link in this)
{
- if (ReferencedTable.EndTable.Name == endTableName)
+ if (link.EndTable.Name == endTableName)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Check if chain of RelationshipLink objects contains an end table with specified name that is BiDi invoked.
+ ///
+ /// Name of the end table.
+ /// Boolean indicating if the BiDi invoked end table was found.
+ public bool ContainsBidiToEndTable(string endTableName)
+ {
+ foreach (RelationshipLink link in this)
+ {
+ if (link.EndTable.Name == endTableName && link.PrecedingPathBiDiInvoked)
{
return true;
}
diff --git a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipLink.cs b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipLink.cs
index 8f8c21e..43db588 100644
--- a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipLink.cs
+++ b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/RelationshipLink.cs
@@ -14,7 +14,9 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
private Table _beginTable;
private Table _endTable;
private bool _root;
+ private bool _biDiInvoked;
private string _tablePath;
+ private bool _precedingPathBiDiInvoked;
private Relationship _filteringRelationship;
///
@@ -25,19 +27,23 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
/// Boolean indicating if the root link in a the relationship chain.
/// Recursive path to the preceding table in the relationship chain.
/// Relationship object for the relationship link.
- public RelationshipLink(Table beginTable, Table endTable, bool root, string precedingTablePath, Relationship filteringRelationship)
+ public RelationshipLink(Table beginTable, Table endTable, bool root, string precedingTablePath, bool precedingPathBiDiInvoked, Relationship filteringRelationship, bool biDiInvoked)
{
_beginTable = beginTable;
_endTable = endTable;
_root = root;
+ _biDiInvoked = biDiInvoked;
if (root)
{
+ //_tablePath = $"'{beginTable.Name}'->{(biDi ? "(BiDi)" : "")}'{endTable.Name}'";
_tablePath = $"'{beginTable.Name}'->'{endTable.Name}'";
}
else
{
+ //_tablePath = $"{precedingTablePath}->{(biDi ? "(BiDi)" : "")}'{endTable.Name}'";
_tablePath = $"{precedingTablePath}->'{endTable.Name}'";
}
+ _precedingPathBiDiInvoked = (precedingPathBiDiInvoked || biDiInvoked);
_filteringRelationship = filteringRelationship;
}
@@ -56,11 +62,21 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
///
public bool Root => _root;
+ ///
+ /// Boolean indicating if the relationship is BiDi and traversing from the many to the one side.
+ ///
+ public bool BiDiInvoked => _biDiInvoked;
+
///
/// Recursive path to the preceding table in the relationship chain.
///
public string TablePath => _tablePath;
+ ///
+ /// Boolean indicating if the relationship is BiDi and traversing from the many to the one side.
+ ///
+ public bool PrecedingPathBiDiInvoked => _precedingPathBiDiInvoked;
+
///
/// Relationship object for the relationship link.
///
diff --git a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs
index 762208e..be6cf41 100644
--- a/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs
+++ b/BismNormalizer/BismNormalizer/TabularCompare/TabularMetadata/TabularModel.cs
@@ -586,13 +586,12 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
{
//beginTable might be the From or the To table in TOM Relationship object; it depends on CrossFilterDirection.
- RelationshipChain referencedTableCollection = new RelationshipChain();
+ RelationshipChainsFromRoot referencedTableCollection = new RelationshipChainsFromRoot();
foreach (Relationship filteringRelationship in beginTable.FindFilteringRelationships())
{
// EndTable can be either the From or the To table of a Relationship object depending on CrossFilteringBehavior
- string endTableName = filteringRelationship.TomRelationship.FromTable.Name == beginTable.Name ? filteringRelationship.TomRelationship.ToTable.Name : filteringRelationship.TomRelationship.FromTable.Name;
-
- RelationshipLink rootLink = new RelationshipLink(beginTable, _tables.FindByName(endTableName), true, "", filteringRelationship);
+ string endTableName = GetEndTableName(beginTable, filteringRelationship, out bool biDi);
+ RelationshipLink rootLink = new RelationshipLink(beginTable, _tables.FindByName(endTableName), true, "", false, filteringRelationship, biDi);
ValidateLink(rootLink, referencedTableCollection);
}
}
@@ -613,15 +612,19 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
}
}
- private void ValidateLink(RelationshipLink link, RelationshipChain chain)
+ private void ValidateLink(RelationshipLink link, RelationshipChainsFromRoot chainsFromRoot)
{
- if (chain.ContainsEndTableName(link.EndTable.Name))
+ if (
+ chainsFromRoot.ContainsEndTableName(link.EndTable.Name)
+ //&& !(link.PrecedingPathBiDiInvoked && !chainsFromRoot.ContainsBidiToEndTable(link.EndTable.Name))
+ //Fix 12/1/2017: we allow 1 ambiguous relationship path as long as only one of the paths is bidi invoked (2 bidis to the same table counts as ambiguous)
+ )
{
// If we are here, we have identified 2 active paths to get to the same table.
// So, the one that was already there in the target should win.
- RelationshipLink otherLink = chain.FindByEndTableName(link.EndTable.Name);
- string rootTableName = chain.FindRoot().BeginTable.Name;
+ RelationshipLink otherLink = chainsFromRoot.FindByEndTableName(link.EndTable.Name);
+ string rootTableName = chainsFromRoot.FindRoot().BeginTable.Name;
if (link.FilteringRelationship.CopiedFromSource)
{
@@ -643,31 +646,47 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
ValidationMessageStatus.Warning));
//remove OTHER ONE from collection as no longer in filtering chain
- chain.RemoveByEndTableName(otherLink.EndTable.Name);
+ chainsFromRoot.RemoveByEndTableName(otherLink.EndTable.Name);
}
}
if (link.FilteringRelationship.TomRelationship.IsActive) //If not, we must have just set it to false above
{
//Add the link to the chain and re-iterate ...
- chain.Add(link);
+ chainsFromRoot.Add(link);
Table beginTable = link.EndTable; //EndTable is now the begin table as iterating next level ...
foreach (Relationship filteringRelationship in beginTable.FindFilteringRelationships())
{
// EndTable can be either the From or the To table of a Relationship object depending on direction of CrossFilteringBehavior
- string endTableName = filteringRelationship.TomRelationship.FromTable.Name == beginTable.Name ? filteringRelationship.TomRelationship.ToTable.Name : filteringRelationship.TomRelationship.FromTable.Name;
+ string endTableName = GetEndTableName(beginTable, filteringRelationship, out bool biDi);
//Need to check if endTableName has already been covered by TablePath to avoid CrossFilteringBehavior leading both ways and never ending loop
if (!link.TablePath.Contains("'" + endTableName + "'"))
{
- RelationshipLink newLink = new RelationshipLink(beginTable, _tables.FindByName(endTableName), false, link.TablePath, filteringRelationship);
- ValidateLink(newLink, chain);
+ RelationshipLink newLink = new RelationshipLink(beginTable, _tables.FindByName(endTableName), false, link.TablePath, link.PrecedingPathBiDiInvoked, filteringRelationship, biDi);
+ ValidateLink(newLink, chainsFromRoot);
}
}
}
}
+ private string GetEndTableName(Table beginTable, Relationship filteringRelationship, out bool biDi)
+ {
+ string endTableName;
+ biDi = false;
+ if (filteringRelationship.TomRelationship.FromTable.Name == beginTable.Name)
+ {
+ endTableName = filteringRelationship.TomRelationship.ToTable.Name;
+ }
+ else
+ {
+ endTableName = filteringRelationship.TomRelationship.FromTable.Name;
+ biDi = true;
+ }
+ return endTableName;
+ }
+
#endregion
#region Variation Cleanup
@@ -1251,20 +1270,6 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
break;
}
- //todo delete
- ////Not sure why switch statement not stopping on "case ObjectType.Perspective:" above. Fudge below. Todo2: test with later build.
- //if (namedObjectSource.ObjectType.ToString() == "Perspective")
- //{
- // foreach (Tom.Perspective tomPerspectiveTarget in tomCultureTarget.Model.Perspectives)
- // {
- // if (namedObjectSource.Name == tomPerspectiveTarget.Name)
- // {
- // namedObjectTarget = tomPerspectiveTarget;
- // break;
- // }
- // }
- //}
-
//If namedObjectTarget is null, the model object doesn't exist in target, so can ignore
if (namedObjectTarget != null)
{
@@ -1275,6 +1280,11 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
if (translation.Object is NamedMetadataObject &&
((NamedMetadataObject)translation.Object).Name == namedObjectSource.Name &&
translation.Object.ObjectType == namedObjectSource.ObjectType &&
+ (
+ //check columns are both in same table (could have columns with same name in different tables)
+ !(translation.Object.Parent.ObjectType == ObjectType.Table && namedObjectSource.Parent.ObjectType == ObjectType.Table) ||
+ (((NamedMetadataObject)translation.Parent).Name == ((NamedMetadataObject)namedObjectSource.Parent).Name)
+ ) &&
translation.Property == translationSource.Property
)
{
@@ -1285,8 +1295,18 @@ namespace BismNormalizer.TabularCompare.TabularMetadata
if (translationTarget != null)
{ //Translation already exists in cultureTarget for this object, so just ensure values match
- //Also decouple from object in model and reset coupling
- translationTarget.Object = namedObjectTarget;
+ //Also decouple from object in model and reset coupling if removed
+ if (translationTarget.Object.IsRemoved)
+ {
+ ObjectTranslation translationTargetReplacement = new ObjectTranslation();
+ translationTargetReplacement.Object = namedObjectTarget;
+ translationTargetReplacement.Property = translationSource.Property;
+ translationTargetReplacement.Value = translationSource.Value;
+ tomCultureTarget.ObjectTranslations.Remove(translationTarget);
+ tomCultureTarget.ObjectTranslations.Add(translationTargetReplacement);
+ translationTarget = translationTargetReplacement;
+ }
+ //translationTarget.Object = namedObjectTarget;
translationTarget.Value = translationSource.Value;
}
else
diff --git a/BismNormalizer/BismNormalizer/TabularCompare/UI/TreeGridView.cs b/BismNormalizer/BismNormalizer/TabularCompare/UI/TreeGridView.cs
index dfe4e91..8a2f1ea 100644
--- a/BismNormalizer/BismNormalizer/TabularCompare/UI/TreeGridView.cs
+++ b/BismNormalizer/BismNormalizer/TabularCompare/UI/TreeGridView.cs
@@ -64,7 +64,7 @@ namespace BismNormalizer.TabularCompare.UI
// Cause edit mode to begin since edit mode is disabled to support
// expanding/collapsing
base.OnKeyDown(e);
- if (!e.Handled)
+ if (!e.Handled && this.Rows.Count > 0)
{
if (e.KeyCode == Keys.F2 && this.CurrentCellAddress.X > -1 && this.CurrentCellAddress.Y >-1)
{
diff --git a/BismNormalizer/BismNormalizer/source.extension.vsixmanifest b/BismNormalizer/BismNormalizer/source.extension.vsixmanifest
index 6c19d2c..5732a62 100644
--- a/BismNormalizer/BismNormalizer/source.extension.vsixmanifest
+++ b/BismNormalizer/BismNormalizer/source.extension.vsixmanifest
@@ -1,7 +1,7 @@
-
+
BISM Normalizer
BISM Normalizer manages Analysis Services tabular models
http://bism-normalizer.com/