} // applyMergeChoices() public void _applyMergeChoicesToNode(MergeInfoData Choices, MergeInfoData.MergeInfoNodePair nodePair, CswNbtNode resultNode) { CswNbtNode Node1 = _CswNbtResources.Nodes[nodePair.Node1Id]; CswNbtNode Node2 = _CswNbtResources.Nodes[nodePair.Node2Id]; if (null != Node1 && null != Node2) { /* * Copy all the values from Node2 into the result and then copy any properties from Node1 into the result that were selected * This is to ensure we copy property values we didn't have to merge. */ resultNode.copyPropertyValuesGeneric(Node2); foreach (MergeInfoData.MergeInfoProperty mergeProp in nodePair.Properties.Where(mergeProp => mergeProp.Choice == 1)) { resultNode.Properties[mergeProp.NodeTypePropId].copyGeneric(Node1.Properties[mergeProp.NodeTypePropId]); } // Set references to new merged node if (Int32.MinValue != nodePair.NodeReferencePropId) { // Find the new nodeid for the value of the reference ICswNbtNodePropNodeReference NodeReferenceProp = resultNode.Properties[nodePair.NodeReferencePropId].AsNodeReference; CswPrimaryKey oldNodeId = NodeReferenceProp.ReferencedNodeId; MergeInfoData.MergeInfoNodePair otherNodePair = Choices.NodePairs.FirstOrDefault(np => np.Node1Id == oldNodeId.ToString() || np.Node2Id == oldNodeId.ToString()); if (null != otherNodePair) { // Set the reference to point to the new merged node NodeReferenceProp.ReferencedNodeId = CswConvert.ToPrimaryKey(otherNodePair.Node2Id); } } // if( Int32.MinValue != nodePair.NodeReferencePropId ) } // if( null != Node1 && null != Node2 ) } // _applyMergeChoicesToNode()
/// <summary> /// Create a dictionary of the unique key values of related nodes /// As a side effect, also populate MergeInfoData.NodePair.NodeReferences /// </summary> private Dictionary <CswDelimitedString, CswPrimaryKey> _getUniqueKeysDict(MergeInfoData.MergeInfoNodePair NodePair, CswNbtNode Node, CswNbtMetaDataNodeTypeProp NodeReferenceProp) { Dictionary <CswDelimitedString, CswPrimaryKey> ret = new Dictionary <CswDelimitedString, CswPrimaryKey>(); char delimiter = '|'; // Find unique properties for this reference's nodetype IEnumerable <CswNbtMetaDataNodeTypeProp> UniqueProps = NodeReferenceProp.getNodeType().getUniqueProps(); // Create a view of nodes that point to the target node via this reference CswNbtView view = new CswNbtView(_CswNbtResources); CswNbtViewRelationship rel1 = view.AddViewRelationship(Node.getNodeType(), false); rel1.NodeIdsToFilterIn.Add(Node.NodeId); CswNbtViewRelationship rel2 = view.AddViewRelationship(rel1, CswEnumNbtViewPropOwnerType.Second, NodeReferenceProp, false); foreach (CswNbtMetaDataNodeTypeProp uniqueProp in UniqueProps) { view.AddViewProperty(rel2, uniqueProp); } // Iterate children and store unique property values in a dictionary key ICswNbtTree tree = _CswNbtResources.Trees.getTreeFromView(view, RequireViewPermissions: false, IncludeHiddenNodes: true, IncludeSystemNodes: true); if (tree.getChildNodeCount() > 0) { tree.goToNthChild(0); for (Int32 c = 0; c < tree.getChildNodeCount(); c++) { tree.goToNthChild(c); CswPrimaryKey thisNodeId = tree.getNodeIdForCurrentPosition(); // Populate MergeInfoData.NodePair.NodeReferences while we're here NodePair.NodeReferences.Add(new MergeInfoData.MergeInfoNodeReference() { NodeId = thisNodeId.ToString(), NodeTypePropId = NodeReferenceProp.PropId }); CswDelimitedString key; if (_AllUniqueKeys.ContainsKey(thisNodeId)) { // If we've seen this node before, use the existing key but override the merge property // (this will allow us to merge correctly if a nodetype has // multiple compound unique references that are all involved in the merge) key = _AllUniqueKeys[thisNodeId]; for (Int32 u = 0; u < UniqueProps.Count(); u++) { if (UniqueProps.ElementAt(u).PropId == NodeReferenceProp.PropId) { // This value will be equal after the merge key[u] = "[mergeresult]"; } } // foreach( CswNbtMetaDataNodeTypeProp uniqueProp in UniqueProps ) } // if( _AllUniqueKeys.ContainsKey( thisNodeId ) ) else { // generate a new key key = new CswDelimitedString(delimiter); foreach (CswNbtMetaDataNodeTypeProp uniqueProp in UniqueProps) { CswNbtTreeNodeProp prop = tree.getChildNodePropsOfNode().FirstOrDefault(p => p.NodeTypePropId == uniqueProp.PropId); if (null != prop) { if (prop.NodeTypePropId == NodeReferenceProp.PropId) { // This value will be equal after the merge key.Add("[mergeresult]"); } else { key.Add(prop.Gestalt); } } else { key.Add(""); } } // foreach( CswNbtMetaDataNodeTypeProp uniqueProp in UniqueProps ) } // if-else( _AllUniqueKeys.ContainsKey( thisNodeId ) ) if (key.Count > 0) { ret.Add(key, thisNodeId); _AllUniqueKeys[thisNodeId] = key; } tree.goToParentNode(); } // for( Int32 c = 0; c < tree.getChildNodeCount(); c++ ) } // if( tree.getChildNodeCount() > 0 ) return(ret); } // _getUniqueKeysDict()
} // getMergeInfo() private void _addMergeNodes(MergeInfoData ret, CswPrimaryKey NodeId1, CswPrimaryKey NodeId2, CswNbtMetaDataNodeTypeProp NodeReferenceProp = null) { CswNbtNode Node1 = _CswNbtResources.Nodes[NodeId1]; CswNbtNode Node2 = _CswNbtResources.Nodes[NodeId2]; if (null != Node1 && null != Node2) { // Make sure there isn't already a node pair for these nodes if (false == ret.NodePairs.Any(np => (np.Node1Id == Node1.NodeId.ToString() && np.Node2Id == Node2.NodeId.ToString()) || (np.Node1Id == Node2.NodeId.ToString() && np.Node2Id == Node1.NodeId.ToString()))) { CswNbtMetaDataNodeType Node1NT = Node1.getNodeType(); MergeInfoData.MergeInfoNodePair NodePair = new MergeInfoData.MergeInfoNodePair(); NodePair.NodeReferences = new Collection <MergeInfoData.MergeInfoNodeReference>(); NodePair.NodeTypeName = Node1NT.NodeTypeName; NodePair.Node1Id = Node1.NodeId.ToString(); NodePair.Node2Id = Node2.NodeId.ToString(); NodePair.Node1Name = Node1.NodeName; NodePair.Node2Name = Node2.NodeName; if (null != NodeReferenceProp) { NodePair.NodeReferencePropId = NodeReferenceProp.PropId; } else { NodePair.NodeReferencePropId = Int32.MinValue; } foreach (CswNbtNodePropWrapper Prop1 in Node1.Properties.Where(p => (null == NodeReferenceProp || p.NodeTypePropId != NodeReferenceProp.PropId))) { CswNbtNodePropWrapper Prop2 = Node2.Properties[Prop1.NodeTypePropId]; if (null == Prop2 || Prop1.Gestalt != Prop2.Gestalt) { NodePair.Properties.Add(new MergeInfoData.MergeInfoProperty() { PropName = Prop1.PropName, NodeTypePropId = Prop1.NodeTypePropId, Node1Value = Prop1.Gestalt, Node2Value = Prop2.Gestalt }); } // if( null == Prop2 || Prop1.Gestalt != Prop2.Gestalt ) } // foreach( CswNbtNodePropWrapper Prop1 in Node1.Properties ) ret.NodePairs.Add(NodePair); // If two nodes that formerly related to each of node1 and node2 now relate to the merged target, // and they now would be compound unique violations, we have to merge those too. // First, find references that point to the merged nodes foreach (CswNbtMetaDataNodeTypeProp thisProp in _CswNbtResources.MetaData.getNodeTypeProps().Where(p => p.IsNodeReference() && p.FkMatches(Node1.getNodeType()))) { // Find unique key sets for nodes using this reference that point to either node1 or node2 Dictionary <CswDelimitedString, CswPrimaryKey> Node1UniqueKeysDict = _getUniqueKeysDict(NodePair, Node1, thisProp); Dictionary <CswDelimitedString, CswPrimaryKey> Node2UniqueKeysDict = _getUniqueKeysDict(NodePair, Node2, thisProp); // Look for redundant keys to indicate a potential unique violation foreach (CswDelimitedString key in Node1UniqueKeysDict.Keys) { if (Node2UniqueKeysDict.ContainsKey(key)) { // unique violation! gotta merge these too. _addMergeNodes(ret, Node1UniqueKeysDict[key], Node2UniqueKeysDict[key], thisProp); } } // foreach( CswDelimitedString key in Node1UniqueKeysDict.Keys ) } // foreach( CswNbtMetaDataNodeTypeProp thisProp in _CswNbtResources.MetaData.getNodeTypeProps().Where( p => p.IsNodeReference() ) ) // Special case: UserSelect properties if (Node1NT.getObjectClassValue() == CswEnumNbtObjectClass.UserClass) { foreach (CswNbtMetaDataNodeTypeProp thisUserSelProp in _CswNbtResources.MetaData.getNodeTypeProps(CswEnumNbtFieldType.UserSelect)) { // Create a view of nodes that point to either merged node via this reference CswNbtView view = new CswNbtView(_CswNbtResources); CswNbtViewRelationship rel1 = view.AddViewRelationship(thisUserSelProp.getNodeType(), false); view.AddViewPropertyAndFilter(rel1, thisUserSelProp, Conjunction: CswEnumNbtFilterConjunction.And, FilterMode: CswEnumNbtFilterMode.Contains, Value: Node1.NodeId.PrimaryKey.ToString()); view.AddViewPropertyAndFilter(rel1, thisUserSelProp, Conjunction: CswEnumNbtFilterConjunction.Or, FilterMode: CswEnumNbtFilterMode.Contains, Value: Node2.NodeId.PrimaryKey.ToString()); // Add nodes with matching UserSelect properties to NodeReferences for later updating ICswNbtTree tree = _CswNbtResources.Trees.getTreeFromView(view, RequireViewPermissions: false, IncludeHiddenNodes: true, IncludeSystemNodes: true); for (Int32 c = 0; c < tree.getChildNodeCount(); c++) { tree.goToNthChild(c); NodePair.NodeReferences.Add(new MergeInfoData.MergeInfoNodeReference() { NodeId = tree.getNodeIdForCurrentPosition().ToString(), NodeTypePropId = thisUserSelProp.PropId }); tree.goToParentNode(); } // for( Int32 c = 0; c < tree.getChildNodeCount(); c++ ) } // foreach( CswNbtMetaDataNodeTypeProp thisUserSelProp in _CswNbtResources.MetaData.getNodeTypeProps( CswEnumNbtFieldType.UserSelect ) ) } // if( Node1NT.getObjectClassValue() == CswEnumNbtObjectClass.UserClass ) } // if(false == ret.NodePairs.Any( ... )) } // if( null != Node1 && null != Node2 ) } // _addMergeNodes()