// Builds a map from foreign key instances to commands, with an entry for every command that may need to // precede some other operation. // // Predecessor commands must precede other commands using those values. There are two kinds of // predecessor: // // - Commands (updates or inserts) inserting FK "targets" (referenced by the foreign key) // - Commands (updates or deletes) deleting FK "sources" (referencing the foreign key) // // To avoid violating constraints, FK values must be created before they are referenced, and // cannot be deleted before their references private KeyToListMap <ForeignKeyValue, UpdateCommand> DetermineForeignKeyPredecessors() { var predecessors = new KeyToListMap <ForeignKeyValue, UpdateCommand>( _keyComparer); foreach (var command in Vertices.OfType <DynamicUpdateCommand>()) { if (ModificationOperator.Update == command.Operator || ModificationOperator.Insert == command.Operator) { foreach (var fkConstraint in _targetMap.EnumerateValues(command.Table)) { ForeignKeyValue fk; if (ForeignKeyValue.TryCreateTargetKey(fkConstraint, command.CurrentValues, true, out fk)) { // if this is an update and the target key is unchanged, there is no // need to add a dependency (from the perspective of the target, the update // is a no-op) ForeignKeyValue originalFK; if (ModificationOperator.Update != command.Operator || !ForeignKeyValue.TryCreateTargetKey(fkConstraint, command.OriginalValues, true, out originalFK) || !_keyComparer.Equals(originalFK, fk)) { predecessors.Add(fk, command); } } } } // register all source predecessors if (ModificationOperator.Update == command.Operator || ModificationOperator.Delete == command.Operator) { foreach (var fkConstraint in _sourceMap.EnumerateValues(command.Table)) { ForeignKeyValue fk; if (ForeignKeyValue.TryCreateSourceKey(fkConstraint, command.OriginalValues, false, out fk)) { // if this is an update and the source key is unchanged, there is no // need to add a dependency (from the perspective of the source, the update // is a no-op) ForeignKeyValue currentFK; if (ModificationOperator.Update != command.Operator || !ForeignKeyValue.TryCreateSourceKey(fkConstraint, command.CurrentValues, false, out currentFK) || !_keyComparer.Equals(currentFK, fk)) { predecessors.Add(fk, command); } } } } } return(predecessors); }
private KeyToListMap <UpdateCommandOrderer.ForeignKeyValue, UpdateCommand> DetermineForeignKeyPredecessors() { KeyToListMap <UpdateCommandOrderer.ForeignKeyValue, UpdateCommand> keyToListMap = new KeyToListMap <UpdateCommandOrderer.ForeignKeyValue, UpdateCommand>((IEqualityComparer <UpdateCommandOrderer.ForeignKeyValue>) this._keyComparer); foreach (DynamicUpdateCommand dynamicUpdateCommand in this.Vertices.OfType <DynamicUpdateCommand>()) { if (dynamicUpdateCommand.Operator == ModificationOperator.Update || ModificationOperator.Insert == dynamicUpdateCommand.Operator) { foreach (ReferentialConstraint enumerateValue in this._targetMap.EnumerateValues((EntitySetBase)dynamicUpdateCommand.Table)) { UpdateCommandOrderer.ForeignKeyValue key1; UpdateCommandOrderer.ForeignKeyValue key2; if (UpdateCommandOrderer.ForeignKeyValue.TryCreateTargetKey(enumerateValue, dynamicUpdateCommand.CurrentValues, true, out key1) && (dynamicUpdateCommand.Operator != ModificationOperator.Update || !UpdateCommandOrderer.ForeignKeyValue.TryCreateTargetKey(enumerateValue, dynamicUpdateCommand.OriginalValues, true, out key2) || !this._keyComparer.Equals(key2, key1))) { keyToListMap.Add(key1, (UpdateCommand)dynamicUpdateCommand); } } } if (dynamicUpdateCommand.Operator == ModificationOperator.Update || ModificationOperator.Delete == dynamicUpdateCommand.Operator) { foreach (ReferentialConstraint enumerateValue in this._sourceMap.EnumerateValues((EntitySetBase)dynamicUpdateCommand.Table)) { UpdateCommandOrderer.ForeignKeyValue key1; UpdateCommandOrderer.ForeignKeyValue key2; if (UpdateCommandOrderer.ForeignKeyValue.TryCreateSourceKey(enumerateValue, dynamicUpdateCommand.OriginalValues, false, out key1) && (dynamicUpdateCommand.Operator != ModificationOperator.Update || !UpdateCommandOrderer.ForeignKeyValue.TryCreateSourceKey(enumerateValue, dynamicUpdateCommand.CurrentValues, false, out key2) || !this._keyComparer.Equals(key2, key1))) { keyToListMap.Add(key1, (UpdateCommand)dynamicUpdateCommand); } } } } return(keyToListMap); }
/// <summary> /// Determines model level dependencies for the current command. Dependencies are based /// on the model operations performed by the command (adding or deleting entities or relationships). /// </summary> internal void GetRequiredAndProducedEntities(UpdateTranslator translator, KeyToListMap <EntityKey, UpdateCommand> addedEntities, KeyToListMap <EntityKey, UpdateCommand> deletedEntities, KeyToListMap <EntityKey, UpdateCommand> addedRelationships, KeyToListMap <EntityKey, UpdateCommand> deletedRelationships) { IList <IEntityStateEntry> stateEntries = GetStateEntries(translator); foreach (IEntityStateEntry stateEntry in stateEntries) { if (!stateEntry.IsRelationship) { if (stateEntry.State == EntityState.Added) { addedEntities.Add(stateEntry.EntityKey, this); } else if (stateEntry.State == EntityState.Deleted) { deletedEntities.Add(stateEntry.EntityKey, this); } } } // process foreign keys if (null != this.OriginalValues) { // if a foreign key being deleted, it 'frees' or 'produces' the referenced key AddReferencedEntities(translator, this.OriginalValues, deletedRelationships); } if (null != this.CurrentValues) { // if a foreign key is being added, if requires the referenced key AddReferencedEntities(translator, this.CurrentValues, addedRelationships); } // process relationships foreach (IEntityStateEntry stateEntry in stateEntries) { if (stateEntry.IsRelationship) { // only worry about the relationship if it is being added or deleted bool isAdded = stateEntry.State == EntityState.Added; if (isAdded || stateEntry.State == EntityState.Deleted) { DbDataRecord record = isAdded ? (DbDataRecord)stateEntry.CurrentValues : stateEntry.OriginalValues; Debug.Assert(2 == record.FieldCount, "non-binary relationship?"); EntityKey end1 = (EntityKey)record[0]; EntityKey end2 = (EntityKey)record[1]; // relationships require the entity when they're added and free the entity when they're deleted... KeyToListMap <EntityKey, UpdateCommand> affected = isAdded ? addedRelationships : deletedRelationships; // both ends are being modified by the relationship affected.Add(end1, this); affected.Add(end2, this); } } } }
internal void GetRequiredAndProducedEntities( UpdateTranslator translator, KeyToListMap <EntityKey, UpdateCommand> addedEntities, KeyToListMap <EntityKey, UpdateCommand> deletedEntities, KeyToListMap <EntityKey, UpdateCommand> addedRelationships, KeyToListMap <EntityKey, UpdateCommand> deletedRelationships) { IList <IEntityStateEntry> stateEntries = this.GetStateEntries(translator); foreach (IEntityStateEntry entityStateEntry in (IEnumerable <IEntityStateEntry>)stateEntries) { if (!entityStateEntry.IsRelationship) { if (entityStateEntry.State == EntityState.Added) { addedEntities.Add(entityStateEntry.EntityKey, this); } else if (entityStateEntry.State == EntityState.Deleted) { deletedEntities.Add(entityStateEntry.EntityKey, this); } } } if (this.OriginalValues != null) { this.AddReferencedEntities(translator, this.OriginalValues, deletedRelationships); } if (this.CurrentValues != null) { this.AddReferencedEntities(translator, this.CurrentValues, addedRelationships); } foreach (IEntityStateEntry entityStateEntry in (IEnumerable <IEntityStateEntry>)stateEntries) { if (entityStateEntry.IsRelationship) { bool flag = entityStateEntry.State == EntityState.Added; if (flag || entityStateEntry.State == EntityState.Deleted) { DbDataRecord dbDataRecord = flag ? (DbDataRecord)entityStateEntry.CurrentValues : entityStateEntry.OriginalValues; EntityKey key1 = (EntityKey)dbDataRecord[0]; EntityKey key2 = (EntityKey)dbDataRecord[1]; KeyToListMap <EntityKey, UpdateCommand> keyToListMap = flag ? addedRelationships : deletedRelationships; keyToListMap.Add(key1, this); keyToListMap.Add(key2, this); } } } }
private void CheckImplication( SchemaConstraints <ViewKeyConstraint> cViewConstraints, SchemaConstraints <ViewKeyConstraint> sViewConstraints) { this.CheckImplicationKeyConstraints(cViewConstraints, sViewConstraints); KeyToListMap <CellGroupValidator.ExtentPair, ViewKeyConstraint> keyToListMap = new KeyToListMap <CellGroupValidator.ExtentPair, ViewKeyConstraint>((IEqualityComparer <CellGroupValidator.ExtentPair>)EqualityComparer <CellGroupValidator.ExtentPair> .Default); foreach (ViewKeyConstraint keyConstraint in cViewConstraints.KeyConstraints) { CellGroupValidator.ExtentPair key = new CellGroupValidator.ExtentPair(keyConstraint.Cell.CQuery.Extent, keyConstraint.Cell.SQuery.Extent); keyToListMap.Add(key, keyConstraint); } foreach (CellGroupValidator.ExtentPair key in keyToListMap.Keys) { ReadOnlyCollection <ViewKeyConstraint> readOnlyCollection = keyToListMap.ListForKey(key); bool flag = false; foreach (ViewKeyConstraint second in readOnlyCollection) { foreach (ViewKeyConstraint keyConstraint in sViewConstraints.KeyConstraints) { if (keyConstraint.Implies(second)) { flag = true; break; } } } if (!flag) { this.m_errorLog.AddEntry(ViewKeyConstraint.GetErrorRecord((IEnumerable <ViewKeyConstraint>)readOnlyCollection)); } } }
// effects: Given a list of node, produces a new list in which all // leaf nodes of the same extent are adjacent to each other. Non-leaf // nodes are also adjacent to each other. CHANGE_ADYA_IMPROVE: Merge with GroupByRightExtent private static List <CellTreeNode> GroupLeafChildrenByExtent(List <CellTreeNode> nodes) { // Keep track of leaf cells for each extent var extentMap = new KeyToListMap <EntitySetBase, CellTreeNode>(EqualityComparer <EntitySetBase> .Default); var newNodes = new List <CellTreeNode>(); foreach (var node in nodes) { var leafNode = node as LeafCellTreeNode; // All non-leaf nodes are added to the result now // leaf nodes are added outside the loop if (leafNode != null) { extentMap.Add(leafNode.LeftCellWrapper.RightCellQuery.Extent, leafNode); } else { newNodes.Add(node); } } // Go through the map and add the leaf children newNodes.AddRange(extentMap.AllValues); return(newNodes); }
internal KeyToListMap <int, TVertex> GenerateConnectedComponents() { int compNum = 0; Dictionary <TVertex, UndirectedGraph <TVertex> .ComponentNum> dictionary = new Dictionary <TVertex, UndirectedGraph <TVertex> .ComponentNum>(this.m_comparer); foreach (TVertex vertex in this.Vertices) { dictionary.Add(vertex, new UndirectedGraph <TVertex> .ComponentNum(compNum)); ++compNum; } foreach (KeyValuePair <TVertex, TVertex> edge in this.Edges) { if (dictionary[edge.Key].componentNum != dictionary[edge.Value].componentNum) { int componentNum1 = dictionary[edge.Value].componentNum; int componentNum2 = dictionary[edge.Key].componentNum; dictionary[edge.Value].componentNum = componentNum2; foreach (TVertex key in dictionary.Keys) { if (dictionary[key].componentNum == componentNum1) { dictionary[key].componentNum = componentNum2; } } } } KeyToListMap <int, TVertex> keyToListMap = new KeyToListMap <int, TVertex>((IEqualityComparer <int>)EqualityComparer <int> .Default); foreach (TVertex vertex in this.Vertices) { int componentNum = dictionary[vertex].componentNum; keyToListMap.Add(componentNum, vertex); } return(keyToListMap); }
private static void InitializeForeignKeyMaps(HashSet <EntityContainer> containers, HashSet <EntitySet> tables, out KeyToListMap <EntitySetBase, ReferentialConstraint> sourceMap, out KeyToListMap <EntitySetBase, ReferentialConstraint> targetMap) { sourceMap = new KeyToListMap <EntitySetBase, ReferentialConstraint>(EqualityComparer <EntitySetBase> .Default); targetMap = new KeyToListMap <EntitySetBase, ReferentialConstraint>(EqualityComparer <EntitySetBase> .Default); // Retrieve relationship ends from each container to populate edges in dependency // graph foreach (EntityContainer container in containers) { foreach (EntitySetBase extent in container.BaseEntitySets) { AssociationSet associationSet = extent as AssociationSet; if (null != associationSet) { AssociationSetEnd source = null; AssociationSetEnd target = null; var ends = associationSet.AssociationSetEnds; if (2 == ends.Count) { // source is equivalent to the "to" end of relationship, target is "from" AssociationType associationType = associationSet.ElementType; bool constraintFound = false; ReferentialConstraint fkConstraint = null; foreach (ReferentialConstraint constraint in associationType.ReferentialConstraints) { if (constraintFound) { Debug.Fail("relationship set should have at most one constraint"); } else { constraintFound = true; } source = associationSet.AssociationSetEnds[constraint.ToRole.Name]; target = associationSet.AssociationSetEnds[constraint.FromRole.Name]; fkConstraint = constraint; } Debug.Assert(constraintFound && null != target && null != source, "relationship set must have at least one constraint"); // only understand binary (foreign key) relationships between entity sets if (null != target && null != source) { if (tables.Contains(target.EntitySet) && tables.Contains(source.EntitySet)) { // Remember metadata sourceMap.Add(source.EntitySet, fkConstraint); targetMap.Add(target.EntitySet, fkConstraint); } } } } } } }
private static KeyToListMap <EntitySetBase, Cell> GroupCellsByExtent( IEnumerable <Cell> cells, ViewTarget viewTarget) { KeyToListMap <EntitySetBase, Cell> keyToListMap = new KeyToListMap <EntitySetBase, Cell>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default); foreach (Cell cell in cells) { CellQuery leftQuery = cell.GetLeftQuery(viewTarget); keyToListMap.Add(leftQuery.Extent, cell); } return(keyToListMap); }
// effects: Given all the cells for a container, groups the cells by // the left query's extent and returns a dictionary for it private static KeyToListMap <EntitySetBase, Cell> GroupCellsByExtent(IEnumerable <Cell> cells, ViewTarget viewTarget) { // Partition cells by extent -- extent is the top node in // the tree. Even for compositions for now? CHANGE_ADYA_FEATURE_COMPOSITION var extentCellMap = new KeyToListMap <EntitySetBase, Cell>(EqualityComparer <EntitySetBase> .Default); foreach (var cell in cells) { // Get the cell query and determine its extent var cellQuery = cell.GetLeftQuery(viewTarget); extentCellMap.Add(cellQuery.Extent, cell); } return(extentCellMap); }
private void InitializeFunctionMappingTranslators( EntitySetBase entitySetBase, EntityContainerMapping mapping) { KeyToListMap <AssociationSet, AssociationEndMember> keyToListMap = new KeyToListMap <AssociationSet, AssociationEndMember>((IEqualityComparer <AssociationSet>)EqualityComparer <AssociationSet> .Default); if (!this.m_functionMappingTranslators.ContainsKey(entitySetBase)) { foreach (EntitySetMapping entitySetMap in mapping.EntitySetMaps) { if (0 < entitySetMap.ModificationFunctionMappings.Count) { this.m_functionMappingTranslators.Add(entitySetMap.Set, ModificationFunctionMappingTranslator.CreateEntitySetTranslator(entitySetMap)); foreach (AssociationSetEnd associationSetEnd in entitySetMap.ImplicitlyMappedAssociationSetEnds) { AssociationSet parentAssociationSet = associationSetEnd.ParentAssociationSet; if (!this.m_functionMappingTranslators.ContainsKey((EntitySetBase)parentAssociationSet)) { this.m_functionMappingTranslators.Add((EntitySetBase)parentAssociationSet, ModificationFunctionMappingTranslator.CreateAssociationSetTranslator((AssociationSetMapping)null)); } AssociationSetEnd oppositeEnd = MetadataHelper.GetOppositeEnd(associationSetEnd); keyToListMap.Add(parentAssociationSet, oppositeEnd.CorrespondingAssociationEndMember); } } else { this.m_functionMappingTranslators.Add(entitySetMap.Set, (ModificationFunctionMappingTranslator)null); } } foreach (AssociationSetMapping relationshipSetMap in mapping.RelationshipSetMaps) { if (relationshipSetMap.ModificationFunctionMapping != null) { AssociationSet set = (AssociationSet)relationshipSetMap.Set; this.m_functionMappingTranslators.Add((EntitySetBase)set, ModificationFunctionMappingTranslator.CreateAssociationSetTranslator(relationshipSetMap)); keyToListMap.AddRange(set, Enumerable.Empty <AssociationEndMember>()); } else if (!this.m_functionMappingTranslators.ContainsKey(relationshipSetMap.Set)) { this.m_functionMappingTranslators.Add(relationshipSetMap.Set, (ModificationFunctionMappingTranslator)null); } } } foreach (AssociationSet key in keyToListMap.Keys) { this.m_associationSetMetadata.Add(key, new AssociationSetMetadata(keyToListMap.EnumerateValues(key))); } }
// effects: A restrictive version of GroupLeafChildrenByExtent -- // only for LASJ and LOJ nodes (works for LOJ only when A LOJ B LOJ C // s.t., B and C are subsets of A -- in our case that is how LOJs are constructed private static List <CellTreeNode> GroupNonAssociativeLeafChildren(List <CellTreeNode> nodes) { // Keep track of leaf cells for each extent ignoring the 0th child var extentMap = new KeyToListMap <EntitySetBase, CellTreeNode>(EqualityComparer <EntitySetBase> .Default); var newNodes = new List <CellTreeNode>(); var nonLeafNodes = new List <CellTreeNode>(); // Add the 0th child newNodes.Add(nodes[0]); for (var i = 1; i < nodes.Count; i++) { var node = nodes[i]; var leafNode = node as LeafCellTreeNode; // All non-leaf nodes are added to the result now // leaf nodes are added outside the loop if (leafNode != null) { extentMap.Add(leafNode.LeftCellWrapper.RightCellQuery.Extent, leafNode); } else { nonLeafNodes.Add(node); } } // Go through the map and add the leaf children // If a group of nodes exists for the 0th node's extent -- place // that group first var firstNode = nodes[0] as LeafCellTreeNode; if (firstNode != null) { var firstExtent = firstNode.LeftCellWrapper.RightCellQuery.Extent; if (extentMap.ContainsKey(firstExtent)) { newNodes.AddRange(extentMap.ListForKey(firstExtent)); // Remove this set from the map extentMap.RemoveKey(firstExtent); } } newNodes.AddRange(extentMap.AllValues); newNodes.AddRange(nonLeafNodes); return(newNodes); }
private QueryRewriter GenerateViewsForExtentAndType( EdmType generatedType, ViewgenContext context, CqlIdentifiers identifiers, KeyToListMap <EntitySetBase, GeneratedView> views, ViewGenMode mode) { QueryRewriter queryRewriter = new QueryRewriter(generatedType, context, mode); queryRewriter.GenerateViewComponents(); CellTreeNode basicView = queryRewriter.BasicView; if (this.m_config.IsNormalTracing) { Helpers.StringTrace("Basic View: "); Helpers.StringTraceLine(basicView.ToString()); } CellTreeNode simplifiedView = ViewGenerator.GenerateSimplifiedView(basicView, queryRewriter.UsedCells); if (this.m_config.IsNormalTracing) { Helpers.StringTraceLine(string.Empty); Helpers.StringTrace("Simplified View: "); Helpers.StringTraceLine(simplifiedView.ToString()); } CqlGenerator cqlGenerator = new CqlGenerator(simplifiedView, queryRewriter.CaseStatements, identifiers, context.MemberMaps.ProjectedSlotMap, queryRewriter.UsedCells.Count, queryRewriter.TopLevelWhereClause, this.m_entityContainerMapping.StorageMappingItemCollection); string eSQL; DbQueryCommandTree commandTree; if (this.m_config.GenerateEsql) { eSQL = cqlGenerator.GenerateEsql(); commandTree = (DbQueryCommandTree)null; } else { eSQL = (string)null; commandTree = cqlGenerator.GenerateCqt(); } GeneratedView generatedView = GeneratedView.CreateGeneratedView(context.Extent, generatedType, commandTree, eSQL, this.m_entityContainerMapping.StorageMappingItemCollection, this.m_config); views.Add(context.Extent, generatedView); return(queryRewriter); }
// effects: Checks if all sViewConstraints are implied by the // constraints in cViewConstraints. If some S-level constraints are // not implied, adds errors/warnings to m_errorLog private void CheckImplication(ViewSchemaConstraints cViewConstraints, ViewSchemaConstraints sViewConstraints) { // Check key constraints // i.e., if S has a key <k1, k2>, C must have a key that is a subset of this CheckImplicationKeyConstraints(cViewConstraints, sViewConstraints); // For updates, we need to ensure the following: for every // extent E, table T pair, some key of E is implied by T's key // Get all key constraints for each extent and each table var extentPairConstraints = new KeyToListMap <ExtentPair, ViewKeyConstraint>(EqualityComparer <ExtentPair> .Default); foreach (var cKeyConstraint in cViewConstraints.KeyConstraints) { var pair = new ExtentPair(cKeyConstraint.Cell.CQuery.Extent, cKeyConstraint.Cell.SQuery.Extent); extentPairConstraints.Add(pair, cKeyConstraint); } // Now check that we guarantee at least one constraint per // extent/table pair foreach (var extentPair in extentPairConstraints.Keys) { var cKeyConstraints = extentPairConstraints.ListForKey(extentPair); var sImpliesSomeC = false; // Go through all key constraints for the extent/table pair, and find one that S implies foreach (var cKeyConstraint in cKeyConstraints) { foreach (var sKeyConstraint in sViewConstraints.KeyConstraints) { if (sKeyConstraint.Implies(cKeyConstraint)) { sImpliesSomeC = true; break; // The implication holds - so no problem } } } if (sImpliesSomeC == false) { // Indicate that at least one key must be ensured on the S-side m_errorLog.AddEntry(ViewKeyConstraint.GetErrorRecord(cKeyConstraints)); } } }
// effects: Given a graph of T, returns a map such that nodes in the // same connected component are in the same list in the KeyToListMap internal KeyToListMap <int, TVertex> GenerateConnectedComponents() { var count = 0; // Set the "component number" for each node var componentMap = new Dictionary <TVertex, ComponentNum>(m_comparer); foreach (var vertex in Vertices) { componentMap.Add(vertex, new ComponentNum(count)); count++; } // Run the connected components algorithm (Page 441 of the CLR -- Cormen, Rivest, Lieserson) foreach (var edge in Edges) { if (componentMap[edge.Key].componentNum != componentMap[edge.Value].componentNum) { // Set the component numbers of both of the nodes to be the same var oldValue = componentMap[edge.Value].componentNum; var newValue = componentMap[edge.Key].componentNum; componentMap[edge.Value].componentNum = newValue; // Since we are resetting edge.Value's component number, find all components whose value // is oldValue and reset it to the new value foreach (var vertex in componentMap.Keys) { if (componentMap[vertex].componentNum == oldValue) { componentMap[vertex].componentNum = newValue; } } } } // Now just grab the vertices which have the same set numbers var result = new KeyToListMap <int, TVertex>(EqualityComparer <int> .Default); foreach (var vertex in Vertices) { var componentNum = componentMap[vertex].componentNum; result.Add(componentNum, vertex); } return(result); }
internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell) { KeyToListMap <MemberProjectedSlot, int> keyToListMap = new KeyToListMap <MemberProjectedSlot, int>((IEqualityComparer <MemberProjectedSlot>)ProjectedSlot.EqualityComparer); for (int index = 0; index < this.m_projectedSlots.Length; ++index) { MemberProjectedSlot projectedSlot = this.m_projectedSlots[index] as MemberProjectedSlot; keyToListMap.Add(projectedSlot, index); } StringBuilder stringBuilder1 = (StringBuilder)null; bool flag = false; foreach (MemberProjectedSlot key in keyToListMap.Keys) { ReadOnlyCollection <int> cSideSlotIndexes = keyToListMap.ListForKey(key); if (cSideSlotIndexes.Count > 1 && !cQuery.AreSlotsEquivalentViaRefConstraints(cSideSlotIndexes)) { flag = true; if (stringBuilder1 == null) { stringBuilder1 = new StringBuilder(Strings.ViewGen_Duplicate_CProperties((object)this.Extent.Name)); stringBuilder1.AppendLine(); } StringBuilder stringBuilder2 = new StringBuilder(); for (int index1 = 0; index1 < cSideSlotIndexes.Count; ++index1) { int index2 = cSideSlotIndexes[index1]; if (index1 != 0) { stringBuilder2.Append(", "); } MemberProjectedSlot projectedSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index2]; stringBuilder2.Append(projectedSlot.ToUserString()); } stringBuilder1.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped((object)key.ToUserString(), (object)stringBuilder2.ToString())); } } if (!flag) { return((ErrorLog.Record)null); } return(new ErrorLog.Record(ViewGenErrorCode.DuplicateCPropertiesMapped, stringBuilder1.ToString(), sourceCell, string.Empty)); }
private static void InitializeForeignKeyMaps( HashSet <EntityContainer> containers, HashSet <EntitySet> tables, out KeyToListMap <EntitySetBase, ReferentialConstraint> sourceMap, out KeyToListMap <EntitySetBase, ReferentialConstraint> targetMap) { sourceMap = new KeyToListMap <EntitySetBase, ReferentialConstraint>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default); targetMap = new KeyToListMap <EntitySetBase, ReferentialConstraint>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default); foreach (EntityContainer container in containers) { foreach (EntitySetBase baseEntitySet in container.BaseEntitySets) { AssociationSet associationSet = baseEntitySet as AssociationSet; if (associationSet != null) { AssociationSetEnd associationSetEnd1 = (AssociationSetEnd)null; AssociationSetEnd associationSetEnd2 = (AssociationSetEnd)null; if (2 == associationSet.AssociationSetEnds.Count) { AssociationType elementType = associationSet.ElementType; bool flag = false; ReferentialConstraint referentialConstraint1 = (ReferentialConstraint)null; foreach (ReferentialConstraint referentialConstraint2 in elementType.ReferentialConstraints) { if (!flag) { flag = true; } associationSetEnd1 = associationSet.AssociationSetEnds[referentialConstraint2.ToRole.Name]; associationSetEnd2 = associationSet.AssociationSetEnds[referentialConstraint2.FromRole.Name]; referentialConstraint1 = referentialConstraint2; } if (associationSetEnd2 != null && associationSetEnd1 != null && (tables.Contains(associationSetEnd2.EntitySet) && tables.Contains(associationSetEnd1.EntitySet))) { sourceMap.Add((EntitySetBase)associationSetEnd1.EntitySet, referentialConstraint1); targetMap.Add((EntitySetBase)associationSetEnd2.EntitySet, referentialConstraint1); } } } } } }
private void AddReferencedEntities(UpdateTranslator translator, PropagatorResult result, KeyToListMap <EntityKey, UpdateCommand> referencedEntities) { foreach (PropagatorResult property in result.GetMemberValues()) { if (property.IsSimple && property.Identifier != PropagatorResult.NullIdentifier && (PropagatorFlags.ForeignKey == (property.PropagatorFlags & PropagatorFlags.ForeignKey))) { foreach (int principal in translator.KeyManager.GetDirectReferences(property.Identifier)) { PropagatorResult owner; if (translator.KeyManager.TryGetIdentifierOwner(principal, out owner) && null != owner.StateEntry) { Debug.Assert(!owner.StateEntry.IsRelationship, "owner must not be a relationship"); referencedEntities.Add(owner.StateEntry.EntityKey, this); } } } } }
private void AddReferencedEntities( UpdateTranslator translator, PropagatorResult result, KeyToListMap <EntityKey, UpdateCommand> referencedEntities) { foreach (PropagatorResult memberValue in result.GetMemberValues()) { if (memberValue.IsSimple && memberValue.Identifier != -1 && PropagatorFlags.ForeignKey == (memberValue.PropagatorFlags & PropagatorFlags.ForeignKey)) { foreach (int directReference in translator.KeyManager.GetDirectReferences(memberValue.Identifier)) { PropagatorResult owner; if (translator.KeyManager.TryGetIdentifierOwner(directReference, out owner) && owner.StateEntry != null) { referencedEntities.Add(owner.StateEntry.EntityKey, this); } } } } }
private static List <CellTreeNode> GroupLeafChildrenByExtent( List <CellTreeNode> nodes) { KeyToListMap <EntitySetBase, CellTreeNode> keyToListMap = new KeyToListMap <EntitySetBase, CellTreeNode>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default); List <CellTreeNode> cellTreeNodeList = new List <CellTreeNode>(); foreach (CellTreeNode node in nodes) { LeafCellTreeNode leafCellTreeNode = node as LeafCellTreeNode; if (leafCellTreeNode != null) { keyToListMap.Add(leafCellTreeNode.LeftCellWrapper.RightCellQuery.Extent, (CellTreeNode)leafCellTreeNode); } else { cellTreeNodeList.Add(node); } } cellTreeNodeList.AddRange(keyToListMap.AllValues); return(cellTreeNodeList); }
internal CellTreeNode GroupByRightExtent(CellTreeNode rootNode) { KeyToListMap <EntitySetBase, LeafCellTreeNode> keyToListMap = new KeyToListMap <EntitySetBase, LeafCellTreeNode>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default); foreach (LeafCellTreeNode child in rootNode.Children) { EntitySetBase extent = child.LeftCellWrapper.RightCellQuery.Extent; keyToListMap.Add(extent, child); } OpCellTreeNode opCellTreeNode1 = new OpCellTreeNode(this.m_viewgenContext, CellTreeOpType.FOJ); foreach (EntitySetBase key in keyToListMap.Keys) { OpCellTreeNode opCellTreeNode2 = new OpCellTreeNode(this.m_viewgenContext, CellTreeOpType.FOJ); foreach (LeafCellTreeNode leafCellTreeNode in keyToListMap.ListForKey(key)) { opCellTreeNode2.Add((CellTreeNode)leafCellTreeNode); } opCellTreeNode1.Add((CellTreeNode)opCellTreeNode2); } return(opCellTreeNode1.Flatten()); }
// requires: The tree rooted at cellTreeNode is an FOJ tree of // LeafCellTreeNodes only, i.e., there is an FOJ node with the // children being LeafCellTreeNodes // // effects: Given a tree rooted at rootNode, ensures that cells // of the same right extent are placed in their own subtree below // cellTreeNode. That is, if there are 3 cells of extent A and 2 of // extent B (i.e., 5 cells with an FOJ on it), the resulting tree has // an FOJ node with two children -- FOJ nodes. These FOJ nodes have 2 // and 3 children internal CellTreeNode GroupByRightExtent(CellTreeNode rootNode) { // A dictionary that maps an extent to the nodes are from that extent // We want a ref comparer here var extentMap = new KeyToListMap <EntitySetBase, LeafCellTreeNode>(EqualityComparer <EntitySetBase> .Default); // CR_Meek_Low: method can be simplified (Map<Extent, OpCellTreeNode>, populate as you go) // (becomes self-documenting) // For each leaf child, find the extent of the child and place it // in extentMap foreach (LeafCellTreeNode childNode in rootNode.Children) { // A cell may contain P, P.PA -- we return P // CHANGE_ADYA_FEATURE_COMPOSITION Need to fix for composition!! var extent = childNode.LeftCellWrapper.RightCellQuery.Extent; // relation or extent to group by Debug.Assert(extent != null, "Each cell must have a right extent"); // Add the childNode as a child of the FOJ tree for "extent" extentMap.Add(extent, childNode); } // Now go through the extent map and create FOJ nodes for each extent // Place the nodes for that extent in the newly-created FOJ subtree // Also add the op node for every node as a child of the final result var result = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ); foreach (var extent in extentMap.Keys) { var extentFojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ); foreach (var childNode in extentMap.ListForKey(extent)) { extentFojNode.Add(childNode); } result.Add(extentFojNode); } // We call Flatten to remove any unnecessary nestings // where an OpNode has only 1 child. return(result.Flatten()); }
private static List <CellTreeNode> GroupNonAssociativeLeafChildren( List <CellTreeNode> nodes) { KeyToListMap <EntitySetBase, CellTreeNode> keyToListMap = new KeyToListMap <EntitySetBase, CellTreeNode>((IEqualityComparer <EntitySetBase>)EqualityComparer <EntitySetBase> .Default); List <CellTreeNode> cellTreeNodeList1 = new List <CellTreeNode>(); List <CellTreeNode> cellTreeNodeList2 = new List <CellTreeNode>(); cellTreeNodeList1.Add(nodes[0]); for (int index = 1; index < nodes.Count; ++index) { CellTreeNode node = nodes[index]; LeafCellTreeNode leafCellTreeNode = node as LeafCellTreeNode; if (leafCellTreeNode != null) { keyToListMap.Add(leafCellTreeNode.LeftCellWrapper.RightCellQuery.Extent, (CellTreeNode)leafCellTreeNode); } else { cellTreeNodeList2.Add(node); } } LeafCellTreeNode node1 = nodes[0] as LeafCellTreeNode; if (node1 != null) { EntitySetBase extent = node1.LeftCellWrapper.RightCellQuery.Extent; if (keyToListMap.ContainsKey(extent)) { cellTreeNodeList1.AddRange((IEnumerable <CellTreeNode>)keyToListMap.ListForKey(extent)); keyToListMap.RemoveKey(extent); } } cellTreeNodeList1.AddRange(keyToListMap.AllValues); cellTreeNodeList1.AddRange((IEnumerable <CellTreeNode>)cellTreeNodeList2); return(cellTreeNodeList1); }
private CellTreeNode ConvertUnionsToNormalizedLOJs(CellTreeNode rootNode) { for (int index = 0; index < rootNode.Children.Count; ++index) { rootNode.Children[index] = this.ConvertUnionsToNormalizedLOJs(rootNode.Children[index]); } if (rootNode.OpType != CellTreeOpType.LOJ || rootNode.Children.Count < 2) { return(rootNode); } OpCellTreeNode opCellTreeNode1 = new OpCellTreeNode(this.m_viewgenContext, rootNode.OpType); List <CellTreeNode> cellTreeNodeList = new List <CellTreeNode>(); OpCellTreeNode opCellTreeNode2 = (OpCellTreeNode)null; HashSet <CellTreeNode> cellTreeNodeSet = (HashSet <CellTreeNode>)null; if (rootNode.Children[0].OpType == CellTreeOpType.IJ) { opCellTreeNode2 = new OpCellTreeNode(this.m_viewgenContext, rootNode.Children[0].OpType); opCellTreeNode1.Add((CellTreeNode)opCellTreeNode2); cellTreeNodeList.AddRange((IEnumerable <CellTreeNode>)rootNode.Children[0].Children); cellTreeNodeSet = new HashSet <CellTreeNode>((IEnumerable <CellTreeNode>)rootNode.Children[0].Children); } else { opCellTreeNode1.Add(rootNode.Children[0]); } foreach (CellTreeNode cellTreeNode in rootNode.Children.Skip <CellTreeNode>(1)) { OpCellTreeNode opCellTreeNode3 = cellTreeNode as OpCellTreeNode; if (opCellTreeNode3 != null && opCellTreeNode3.OpType == CellTreeOpType.Union) { cellTreeNodeList.AddRange((IEnumerable <CellTreeNode>)opCellTreeNode3.Children); } else { cellTreeNodeList.Add(cellTreeNode); } } KeyToListMap <EntitySet, LeafCellTreeNode> keyToListMap1 = new KeyToListMap <EntitySet, LeafCellTreeNode>((IEqualityComparer <EntitySet>)EqualityComparer <EntitySet> .Default); foreach (CellTreeNode child in cellTreeNodeList) { LeafCellTreeNode leaf = child as LeafCellTreeNode; if (leaf != null) { EntitySetBase leafNodeTable = (EntitySetBase)BasicViewGenerator.GetLeafNodeTable(leaf); if (leafNodeTable != null) { keyToListMap1.Add((EntitySet)leafNodeTable, leaf); } } else if (cellTreeNodeSet != null && cellTreeNodeSet.Contains(child)) { opCellTreeNode2.Add(child); } else { opCellTreeNode1.Add(child); } } foreach (KeyValuePair <EntitySet, List <LeafCellTreeNode> > keyValuePair in keyToListMap1.KeyValuePairs.Where <KeyValuePair <EntitySet, List <LeafCellTreeNode> > >((Func <KeyValuePair <EntitySet, List <LeafCellTreeNode> >, bool>)(m => m.Value.Count > 1)).ToArray <KeyValuePair <EntitySet, List <LeafCellTreeNode> > >()) { keyToListMap1.RemoveKey(keyValuePair.Key); foreach (LeafCellTreeNode leafCellTreeNode in keyValuePair.Value) { if (cellTreeNodeSet != null && cellTreeNodeSet.Contains((CellTreeNode)leafCellTreeNode)) { opCellTreeNode2.Add((CellTreeNode)leafCellTreeNode); } else { opCellTreeNode1.Add((CellTreeNode)leafCellTreeNode); } } } KeyToListMap <EntitySet, EntitySet> keyToListMap2 = new KeyToListMap <EntitySet, EntitySet>((IEqualityComparer <EntitySet>)EqualityComparer <EntitySet> .Default); Dictionary <EntitySet, OpCellTreeNode> dictionary = new Dictionary <EntitySet, OpCellTreeNode>((IEqualityComparer <EntitySet>)EqualityComparer <EntitySet> .Default); foreach (KeyValuePair <EntitySet, List <LeafCellTreeNode> > keyValuePair in keyToListMap1.KeyValuePairs) { EntitySet key = keyValuePair.Key; foreach (EntitySet fkOverPkDependent in BasicViewGenerator.GetFKOverPKDependents(key)) { ReadOnlyCollection <LeafCellTreeNode> valueCollection; if (keyToListMap1.TryGetListForKey(fkOverPkDependent, out valueCollection) && (cellTreeNodeSet == null || !cellTreeNodeSet.Contains((CellTreeNode)valueCollection.Single <LeafCellTreeNode>()))) { keyToListMap2.Add(key, fkOverPkDependent); } } OpCellTreeNode opCellTreeNode3 = new OpCellTreeNode(this.m_viewgenContext, CellTreeOpType.LOJ); opCellTreeNode3.Add((CellTreeNode)keyValuePair.Value.Single <LeafCellTreeNode>()); dictionary.Add(key, opCellTreeNode3); } Dictionary <EntitySet, EntitySet> nestedExtents = new Dictionary <EntitySet, EntitySet>((IEqualityComparer <EntitySet>)EqualityComparer <EntitySet> .Default); foreach (KeyValuePair <EntitySet, List <EntitySet> > keyValuePair in keyToListMap2.KeyValuePairs) { EntitySet key = keyValuePair.Key; foreach (EntitySet entitySet in keyValuePair.Value) { OpCellTreeNode opCellTreeNode3; if (dictionary.TryGetValue(entitySet, out opCellTreeNode3) && !nestedExtents.ContainsKey(entitySet) && !BasicViewGenerator.CheckLOJCycle(entitySet, key, nestedExtents)) { dictionary[keyValuePair.Key].Add((CellTreeNode)opCellTreeNode3); nestedExtents.Add(entitySet, key); } } } foreach (KeyValuePair <EntitySet, OpCellTreeNode> keyValuePair in dictionary) { if (!nestedExtents.ContainsKey(keyValuePair.Key)) { OpCellTreeNode opCellTreeNode3 = keyValuePair.Value; if (cellTreeNodeSet != null && cellTreeNodeSet.Contains(opCellTreeNode3.Children[0])) { opCellTreeNode2.Add((CellTreeNode)opCellTreeNode3); } else { opCellTreeNode1.Add((CellTreeNode)opCellTreeNode3); } } } return(opCellTreeNode1.Flatten()); }
internal FunctionImportStructuralTypeMappingKB( IEnumerable<FunctionImportStructuralTypeMapping> structuralTypeMappings, ItemCollection itemCollection) { DebugCheck.NotNull(structuralTypeMappings); DebugCheck.NotNull(itemCollection); m_itemCollection = itemCollection; // If no specific type mapping. if (structuralTypeMappings.Count() == 0) { // Initialize with defaults. ReturnTypeColumnsRenameMapping = new Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping>(); NormalizedEntityTypeMappings = new ReadOnlyCollection<FunctionImportNormalizedEntityTypeMapping>( new List<FunctionImportNormalizedEntityTypeMapping>()); DiscriminatorColumns = new ReadOnlyCollection<string>(new List<string>()); MappedEntityTypes = new ReadOnlyCollection<EntityType>(new List<EntityType>()); return; } var entityTypeMappings = structuralTypeMappings.OfType<FunctionImportEntityTypeMapping>(); // FunctionImportEntityTypeMapping if (null != entityTypeMappings && null != entityTypeMappings.FirstOrDefault()) { var isOfTypeEntityTypeColumnsRenameMapping = new Dictionary<EntityType, Collection<FunctionImportReturnTypePropertyMapping>>(); var entityTypeColumnsRenameMapping = new Dictionary<EntityType, Collection<FunctionImportReturnTypePropertyMapping>>(); var normalizedEntityTypeMappings = new List<FunctionImportNormalizedEntityTypeMapping>(); // Collect all mapped entity types. MappedEntityTypes = entityTypeMappings .SelectMany(mapping => mapping.GetMappedEntityTypes(m_itemCollection)) .Distinct() .ToList() .AsReadOnly(); // Collect all discriminator columns. DiscriminatorColumns = entityTypeMappings .SelectMany(mapping => mapping.GetDiscriminatorColumns()) .Distinct() .ToList() .AsReadOnly(); m_entityTypeLineInfos = new KeyToListMap<EntityType, LineInfo>(EqualityComparer<EntityType>.Default); m_isTypeOfLineInfos = new KeyToListMap<EntityType, LineInfo>(EqualityComparer<EntityType>.Default); foreach (var entityTypeMapping in entityTypeMappings) { // Remember LineInfos for error reporting. foreach (var entityType in entityTypeMapping.EntityTypes) { m_entityTypeLineInfos.Add(entityType, entityTypeMapping.LineInfo); } foreach (var isTypeOf in entityTypeMapping.IsOfTypeEntityTypes) { m_isTypeOfLineInfos.Add(isTypeOf, entityTypeMapping.LineInfo); } // Create map from column name to condition. var columnMap = entityTypeMapping.Conditions.ToDictionary( condition => condition.ColumnName, condition => condition); // Align conditions with discriminator columns. var columnMappings = new List<FunctionImportEntityTypeMappingCondition>(DiscriminatorColumns.Count); for (var i = 0; i < DiscriminatorColumns.Count; i++) { var discriminatorColumn = DiscriminatorColumns[i]; FunctionImportEntityTypeMappingCondition mappingCondition; if (columnMap.TryGetValue(discriminatorColumn, out mappingCondition)) { columnMappings.Add(mappingCondition); } else { // Null indicates the value for this discriminator doesn't matter. columnMappings.Add(null); } } // Create bit map for implied entity types. var impliedEntityTypesBitMap = new bool[MappedEntityTypes.Count]; var impliedEntityTypesSet = new Set<EntityType>(entityTypeMapping.GetMappedEntityTypes(m_itemCollection)); for (var i = 0; i < MappedEntityTypes.Count; i++) { impliedEntityTypesBitMap[i] = impliedEntityTypesSet.Contains(MappedEntityTypes[i]); } // Construct normalized mapping. normalizedEntityTypeMappings.Add( new FunctionImportNormalizedEntityTypeMapping(this, columnMappings, new BitArray(impliedEntityTypesBitMap))); // Construct the rename mappings by adding isTypeOf types and specific entity types to the corresponding lists. foreach (var isOfType in entityTypeMapping.IsOfTypeEntityTypes) { if (!isOfTypeEntityTypeColumnsRenameMapping.Keys.Contains(isOfType)) { isOfTypeEntityTypeColumnsRenameMapping.Add( isOfType, new Collection<FunctionImportReturnTypePropertyMapping>()); } foreach (var rename in entityTypeMapping.ColumnsRenameList) { isOfTypeEntityTypeColumnsRenameMapping[isOfType].Add(rename); } } foreach (var entityType in entityTypeMapping.EntityTypes) { if (!entityTypeColumnsRenameMapping.Keys.Contains(entityType)) { entityTypeColumnsRenameMapping.Add(entityType, new Collection<FunctionImportReturnTypePropertyMapping>()); } foreach (var rename in entityTypeMapping.ColumnsRenameList) { entityTypeColumnsRenameMapping[entityType].Add(rename); } } } ReturnTypeColumnsRenameMapping = new FunctionImportReturnTypeEntityTypeColumnsRenameBuilder( isOfTypeEntityTypeColumnsRenameMapping, entityTypeColumnsRenameMapping) .ColumnRenameMapping; NormalizedEntityTypeMappings = new ReadOnlyCollection<FunctionImportNormalizedEntityTypeMapping>( normalizedEntityTypeMappings); } else { // FunctionImportComplexTypeMapping Debug.Assert( structuralTypeMappings.First() is FunctionImportComplexTypeMapping, "only two types can have renames, complexType and entityType"); var complexTypeMappings = structuralTypeMappings.Cast<FunctionImportComplexTypeMapping>(); Debug.Assert( complexTypeMappings.Count() == 1, "how come there are more than 1, complex type cannot derive from other complex type"); ReturnTypeColumnsRenameMapping = new Dictionary<string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping>(); foreach (var rename in complexTypeMappings.First().ColumnsRenameList) { var columnRenameMapping = new FunctionImportReturnTypeStructuralTypeColumnRenameMapping(rename.CMember); columnRenameMapping.AddRename( new FunctionImportReturnTypeStructuralTypeColumn( rename.SColumn, complexTypeMappings.First().ReturnType, false, rename.LineInfo)); ReturnTypeColumnsRenameMapping.Add(rename.CMember, columnRenameMapping); } // Initialize the entity mapping data as empty. NormalizedEntityTypeMappings = new ReadOnlyCollection<FunctionImportNormalizedEntityTypeMapping>( new List<FunctionImportNormalizedEntityTypeMapping>()); DiscriminatorColumns = new ReadOnlyCollection<string>( new List<string> { }); MappedEntityTypes = new ReadOnlyCollection<EntityType>( new List<EntityType> { }); } }
private CellTreeNode ConvertUnionsToNormalizedLOJs(CellTreeNode rootNode) { // Recursively, transform the subtrees rooted at rootNode's children. for (var i = 0; i < rootNode.Children.Count; i++) { // Method modifies input as well. rootNode.Children[i] = ConvertUnionsToNormalizedLOJs(rootNode.Children[i]); } // We rewrite only LOJs. if (rootNode.OpType != CellTreeOpType.LOJ || rootNode.Children.Count < 2) { return(rootNode); } // Create the resulting LOJ node. var result = new OpCellTreeNode(m_viewgenContext, rootNode.OpType); // Create working collection for the LOJ children. var children = new List <CellTreeNode>(); // If rootNode looks something like ((V0 IJ V1) LOJ V2 LOJ V3), // and it turns out that there are FK associations from V2 or V3 pointing, let's say at V0, // then we want to rewrite the result as (V1 IJ (V0 LOJ V2 LOJ V3)). // If we don't do this, then plan compiler won't have a chance to eliminate LOJ V2 LOJ V3. // Hence, flatten the first child or rootNode if it's IJ, but remember that its parts are driving nodes for the LOJ, // so that we don't accidentally nest them. OpCellTreeNode resultIJDriver = null; HashSet <CellTreeNode> resultIJDriverChildren = null; if (rootNode.Children[0].OpType == CellTreeOpType.IJ) { // Create empty resultIJDriver node and add it as the first child (driving) into the LOJ result. resultIJDriver = new OpCellTreeNode(m_viewgenContext, rootNode.Children[0].OpType); result.Add(resultIJDriver); children.AddRange(rootNode.Children[0].Children); resultIJDriverChildren = new HashSet <CellTreeNode>(rootNode.Children[0].Children); } else { result.Add(rootNode.Children[0]); } // Flatten unions in non-driving nodes: (V0 LOJ (V1 Union V2 Union V3)) -> (V0 LOJ V1 LOJ V2 LOJ V3) foreach (var child in rootNode.Children.Skip(1)) { var opNode = child as OpCellTreeNode; if (opNode != null && opNode.OpType == CellTreeOpType.Union) { children.AddRange(opNode.Children); } else { children.Add(child); } } // A dictionary that maps an extent to the nodes that are from that extent. // We want a ref comparer here. var extentMap = new KeyToListMap <EntitySet, LeafCellTreeNode>(EqualityComparer <EntitySet> .Default); // Note that we skip non-leaf nodes (non-leaf nodes don't have FKs) and attach them directly to the result. foreach (var child in children) { var leaf = child as LeafCellTreeNode; if (leaf != null) { EntitySetBase extent = GetLeafNodeTable(leaf); if (extent != null) { extentMap.Add((EntitySet)extent, leaf); } } else { if (resultIJDriverChildren != null && resultIJDriverChildren.Contains(child)) { resultIJDriver.Add(child); } else { result.Add(child); } } } // We only deal with simple cases - one node per extent, remove the rest from children and attach directly to result. var nonTrivial = extentMap.KeyValuePairs.Where(m => m.Value.Count > 1).ToArray(); foreach (var m in nonTrivial) { extentMap.RemoveKey(m.Key); foreach (var n in m.Value) { if (resultIJDriverChildren != null && resultIJDriverChildren.Contains(n)) { resultIJDriver.Add(n); } else { result.Add(n); } } } Debug.Assert(extentMap.KeyValuePairs.All(m => m.Value.Count == 1), "extentMap must map to single nodes only."); // Walk the extents in extentMap and for each extent build PK -> FK1(PK1), FK2(PK2), ... map // where PK is the primary key of the left extent, and FKn(PKn) is an FK of a right extent that // points to the PK of the left extent and is based on the PK columns of the right extent. // Example: // table tBaseType(Id int, c1 int), PK = (tBaseType.Id) // table tDerivedType1(Id int, c2 int), PK1 = (tDerivedType1.Id), FK1 = (tDerivedType1.Id -> tBaseType.Id) // table tDerivedType2(Id int, c3 int), PK2 = (tDerivedType2.Id), FK2 = (tDerivedType2.Id -> tBaseType.Id) // Will produce: // (tBaseType) -> (tDerivedType1, tDerivedType2) var pkFkMap = new KeyToListMap <EntitySet, EntitySet>(EqualityComparer <EntitySet> .Default); // Also for each extent in extentMap, build another map (extent) -> (LOJ node). // It will be used to construct the nesting in the next step. var extentLOJs = new Dictionary <EntitySet, OpCellTreeNode>(EqualityComparer <EntitySet> .Default); foreach (var extentInfo in extentMap.KeyValuePairs) { var principalExtent = extentInfo.Key; foreach (var fkExtent in GetFKOverPKDependents(principalExtent)) { // Only track fkExtents that are in extentMap. ReadOnlyCollection <LeafCellTreeNode> nodes; if (extentMap.TryGetListForKey(fkExtent, out nodes)) { // Make sure that we are not adding resultIJDriverChildren as FK dependents - we do not want them to get nested. if (resultIJDriverChildren == null || !resultIJDriverChildren.Contains(nodes.Single())) { pkFkMap.Add(principalExtent, fkExtent); } } } var extentLojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.LOJ); extentLojNode.Add(extentInfo.Value.Single()); extentLOJs.Add(principalExtent, extentLojNode); } // Construct LOJ nesting inside extentLOJs based on the information in pkFkMap. // Also, track nested extents using nestedExtents. // Example: // We start with nestedExtents empty extentLOJs as such: // tBaseType -> LOJ(BaseTypeNode) // tDerivedType1 -> LOJ(DerivedType1Node)* // tDerivedType2 -> LOJ(DerivedType2Node)** // Note that * and ** represent object references. So each time something is nested, // we don't clone, but nest the original LOJ. When we get to processing the extent of that LOJ, // we might add other children to that nested LOJ. // As we walk pkFkMap, we end up with this: // tBaseType -> LOJ(BaseTypeNode, LOJ(DerivedType1Node)*, LOJ(DerivedType2Node)**) // tDerivedType1 -> LOJ(DerivedType1Node)* // tDerivedType2 -> LOJ(DerivedType2Node)** // nestedExtens = (tDerivedType1, tDerivedType2) var nestedExtents = new Dictionary <EntitySet, EntitySet>(EqualityComparer <EntitySet> .Default); foreach (var m in pkFkMap.KeyValuePairs) { var principalExtent = m.Key; foreach (var fkExtent in m.Value) { OpCellTreeNode fkExtentLOJ; if (extentLOJs.TryGetValue(fkExtent, out fkExtentLOJ) && // make sure we don't nest twice and we don't create a cycle. !nestedExtents.ContainsKey(fkExtent) && !CheckLOJCycle(fkExtent, principalExtent, nestedExtents)) { extentLOJs[m.Key].Add(fkExtentLOJ); nestedExtents.Add(fkExtent, principalExtent); } } } // Now we need to grab the LOJs that have not been nested and add them to the result. // All LOJs that have been nested must be somewhere inside the LOJs that have not been nested, // so they as well end up in the result as part of the unnested ones. foreach (var m in extentLOJs) { if (!nestedExtents.ContainsKey(m.Key)) { // extentLOJ represents (Vx LOJ Vy LOJ(Vm LOJ Vn)) where Vx is the original node from rootNode.Children or resultIJDriverChildren. var extentLOJ = m.Value; if (resultIJDriverChildren != null && resultIJDriverChildren.Contains(extentLOJ.Children[0])) { resultIJDriver.Add(extentLOJ); } else { result.Add(extentLOJ); } } } return(result.Flatten()); }
// requires: All slots in this are join tree slots // This method is called for an S-side query // cQuery is the corresponding C-side query in the cell // sourceCell is the original cell for "this" and cQuery // effects: Checks if any of the columns in "this" are mapped to multiple properties in cQuery. If so, // returns an error record about the duplicated slots internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell) { // slotMap stores the slots on the S-side and the // C-side properties that it maps to var slotMap = new KeyToListMap <MemberProjectedSlot, int>(ProjectedSlot.EqualityComparer); // Note that this does work for self-association. In the manager // employee example, ManagerId and EmployeeId from the SEmployee // table map to the two ends -- Manager.ManagerId and // Employee.EmployeeId in the C Space for (var i = 0; i < m_projectedSlots.Length; i++) { var projectedSlot = m_projectedSlots[i]; var slot = projectedSlot as MemberProjectedSlot; Debug.Assert(slot != null, "All slots for this method must be JoinTreeSlots"); slotMap.Add(slot, i); } StringBuilder builder = null; // Now determine the entries that have more than one integer per slot var isErrorSituation = false; foreach (var slot in slotMap.Keys) { var indexes = slotMap.ListForKey(slot); Debug.Assert(indexes.Count >= 1, "Each slot must have one index at least"); if (indexes.Count > 1 && cQuery.AreSlotsEquivalentViaRefConstraints(indexes) == false) { // The column is mapped to more than one property and it // failed the "association corresponds to referential // constraints" check isErrorSituation = true; if (builder == null) { builder = new StringBuilder(Strings.ViewGen_Duplicate_CProperties(Extent.Name)); builder.AppendLine(); } var tmpBuilder = new StringBuilder(); for (var i = 0; i < indexes.Count; i++) { var index = indexes[i]; if (i != 0) { tmpBuilder.Append(", "); } // The slot must be a JoinTreeSlot. If it isn't it is an internal error var cSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index]; tmpBuilder.Append(cSlot.ToUserString()); } builder.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped(slot.ToUserString(), tmpBuilder.ToString())); } } if (false == isErrorSituation) { return(null); } var record = new ErrorLog.Record(ViewGenErrorCode.DuplicateCPropertiesMapped, builder.ToString(), sourceCell, String.Empty); return(record); }
// effects: Given all the cells for a container, groups the cells by // the left query's extent and returns a dictionary for it private static KeyToListMap<EntitySetBase, Cell> GroupCellsByExtent(IEnumerable<Cell> cells, ViewTarget viewTarget) { // Partition cells by extent -- extent is the top node in // the tree. Even for compositions for now? CHANGE_ADYA_FEATURE_COMPOSITION var extentCellMap = new KeyToListMap<EntitySetBase, Cell>(EqualityComparer<EntitySetBase>.Default); foreach (var cell in cells) { // Get the cell query and determine its extent var cellQuery = cell.GetLeftQuery(viewTarget); extentCellMap.Add(cellQuery.Extent, cell); } return extentCellMap; }
private CellTreeNode ConvertUnionsToNormalizedLOJs(CellTreeNode rootNode) { // Recursively, transform the subtrees rooted at rootNode's children. for (var i = 0; i < rootNode.Children.Count; i++) { // Method modifies input as well. rootNode.Children[i] = ConvertUnionsToNormalizedLOJs(rootNode.Children[i]); } // We rewrite only LOJs. if (rootNode.OpType != CellTreeOpType.LOJ || rootNode.Children.Count < 2) { return rootNode; } // Create the resulting LOJ node. var result = new OpCellTreeNode(m_viewgenContext, rootNode.OpType); // Create working collection for the LOJ children. var children = new List<CellTreeNode>(); // If rootNode looks something like ((V0 IJ V1) LOJ V2 LOJ V3), // and it turns out that there are FK associations from V2 or V3 pointing, let's say at V0, // then we want to rewrite the result as (V1 IJ (V0 LOJ V2 LOJ V3)). // If we don't do this, then plan compiler won't have a chance to eliminate LOJ V2 LOJ V3. // Hence, flatten the first child or rootNode if it's IJ, but remember that its parts are driving nodes for the LOJ, // so that we don't accidentally nest them. OpCellTreeNode resultIJDriver = null; HashSet<CellTreeNode> resultIJDriverChildren = null; if (rootNode.Children[0].OpType == CellTreeOpType.IJ) { // Create empty resultIJDriver node and add it as the first child (driving) into the LOJ result. resultIJDriver = new OpCellTreeNode(m_viewgenContext, rootNode.Children[0].OpType); result.Add(resultIJDriver); children.AddRange(rootNode.Children[0].Children); resultIJDriverChildren = new HashSet<CellTreeNode>(rootNode.Children[0].Children); } else { result.Add(rootNode.Children[0]); } // Flatten unions in non-driving nodes: (V0 LOJ (V1 Union V2 Union V3)) -> (V0 LOJ V1 LOJ V2 LOJ V3) foreach (var child in rootNode.Children.Skip(1)) { var opNode = child as OpCellTreeNode; if (opNode != null && opNode.OpType == CellTreeOpType.Union) { children.AddRange(opNode.Children); } else { children.Add(child); } } // A dictionary that maps an extent to the nodes that are from that extent. // We want a ref comparer here. var extentMap = new KeyToListMap<EntitySet, LeafCellTreeNode>(EqualityComparer<EntitySet>.Default); // Note that we skip non-leaf nodes (non-leaf nodes don't have FKs) and attach them directly to the result. foreach (var child in children) { var leaf = child as LeafCellTreeNode; if (leaf != null) { EntitySetBase extent = GetLeafNodeTable(leaf); if (extent != null) { extentMap.Add((EntitySet)extent, leaf); } } else { if (resultIJDriverChildren != null && resultIJDriverChildren.Contains(child)) { resultIJDriver.Add(child); } else { result.Add(child); } } } // We only deal with simple cases - one node per extent, remove the rest from children and attach directly to result. var nonTrivial = extentMap.KeyValuePairs.Where(m => m.Value.Count > 1).ToArray(); foreach (var m in nonTrivial) { extentMap.RemoveKey(m.Key); foreach (var n in m.Value) { if (resultIJDriverChildren != null && resultIJDriverChildren.Contains(n)) { resultIJDriver.Add(n); } else { result.Add(n); } } } Debug.Assert(extentMap.KeyValuePairs.All(m => m.Value.Count == 1), "extentMap must map to single nodes only."); // Walk the extents in extentMap and for each extent build PK -> FK1(PK1), FK2(PK2), ... map // where PK is the primary key of the left extent, and FKn(PKn) is an FK of a right extent that // points to the PK of the left extent and is based on the PK columns of the right extent. // Example: // table tBaseType(Id int, c1 int), PK = (tBaseType.Id) // table tDerivedType1(Id int, c2 int), PK1 = (tDerivedType1.Id), FK1 = (tDerivedType1.Id -> tBaseType.Id) // table tDerivedType2(Id int, c3 int), PK2 = (tDerivedType2.Id), FK2 = (tDerivedType2.Id -> tBaseType.Id) // Will produce: // (tBaseType) -> (tDerivedType1, tDerivedType2) var pkFkMap = new KeyToListMap<EntitySet, EntitySet>(EqualityComparer<EntitySet>.Default); // Also for each extent in extentMap, build another map (extent) -> (LOJ node). // It will be used to construct the nesting in the next step. var extentLOJs = new Dictionary<EntitySet, OpCellTreeNode>(EqualityComparer<EntitySet>.Default); foreach (var extentInfo in extentMap.KeyValuePairs) { var principalExtent = extentInfo.Key; foreach (var fkExtent in GetFKOverPKDependents(principalExtent)) { // Only track fkExtents that are in extentMap. ReadOnlyCollection<LeafCellTreeNode> nodes; if (extentMap.TryGetListForKey(fkExtent, out nodes)) { // Make sure that we are not adding resultIJDriverChildren as FK dependents - we do not want them to get nested. if (resultIJDriverChildren == null || !resultIJDriverChildren.Contains(nodes.Single())) { pkFkMap.Add(principalExtent, fkExtent); } } } var extentLojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.LOJ); extentLojNode.Add(extentInfo.Value.Single()); extentLOJs.Add(principalExtent, extentLojNode); } // Construct LOJ nesting inside extentLOJs based on the information in pkFkMap. // Also, track nested extents using nestedExtents. // Example: // We start with nestedExtents empty extentLOJs as such: // tBaseType -> LOJ(BaseTypeNode) // tDerivedType1 -> LOJ(DerivedType1Node)* // tDerivedType2 -> LOJ(DerivedType2Node)** // Note that * and ** represent object references. So each time something is nested, // we don't clone, but nest the original LOJ. When we get to processing the extent of that LOJ, // we might add other children to that nested LOJ. // As we walk pkFkMap, we end up with this: // tBaseType -> LOJ(BaseTypeNode, LOJ(DerivedType1Node)*, LOJ(DerivedType2Node)**) // tDerivedType1 -> LOJ(DerivedType1Node)* // tDerivedType2 -> LOJ(DerivedType2Node)** // nestedExtens = (tDerivedType1, tDerivedType2) var nestedExtents = new Dictionary<EntitySet, EntitySet>(EqualityComparer<EntitySet>.Default); foreach (var m in pkFkMap.KeyValuePairs) { var principalExtent = m.Key; foreach (var fkExtent in m.Value) { OpCellTreeNode fkExtentLOJ; if (extentLOJs.TryGetValue(fkExtent, out fkExtentLOJ) && // make sure we don't nest twice and we don't create a cycle. !nestedExtents.ContainsKey(fkExtent) && !CheckLOJCycle(fkExtent, principalExtent, nestedExtents)) { extentLOJs[m.Key].Add(fkExtentLOJ); nestedExtents.Add(fkExtent, principalExtent); } } } // Now we need to grab the LOJs that have not been nested and add them to the result. // All LOJs that have been nested must be somewhere inside the LOJs that have not been nested, // so they as well end up in the result as part of the unnested ones. foreach (var m in extentLOJs) { if (!nestedExtents.ContainsKey(m.Key)) { // extentLOJ represents (Vx LOJ Vy LOJ(Vm LOJ Vn)) where Vx is the original node from rootNode.Children or resultIJDriverChildren. var extentLOJ = m.Value; if (resultIJDriverChildren != null && resultIJDriverChildren.Contains(extentLOJ.Children[0])) { resultIJDriver.Add(extentLOJ); } else { result.Add(extentLOJ); } } } return result.Flatten(); }
// requires: The tree rooted at cellTreeNode is an FOJ tree of // LeafCellTreeNodes only, i.e., there is an FOJ node with the // children being LeafCellTreeNodes // // effects: Given a tree rooted at rootNode, ensures that cells // of the same right extent are placed in their own subtree below // cellTreeNode. That is, if there are 3 cells of extent A and 2 of // extent B (i.e., 5 cells with an FOJ on it), the resulting tree has // an FOJ node with two children -- FOJ nodes. These FOJ nodes have 2 // and 3 children internal CellTreeNode GroupByRightExtent(CellTreeNode rootNode) { // A dictionary that maps an extent to the nodes are from that extent // We want a ref comparer here var extentMap = new KeyToListMap<EntitySetBase, LeafCellTreeNode>(EqualityComparer<EntitySetBase>.Default); // CR_Meek_Low: method can be simplified (Map<Extent, OpCellTreeNode>, populate as you go) // (becomes self-documenting) // For each leaf child, find the extent of the child and place it // in extentMap foreach (LeafCellTreeNode childNode in rootNode.Children) { // A cell may contain P, P.PA -- we return P // CHANGE_ADYA_FEATURE_COMPOSITION Need to fix for composition!! var extent = childNode.LeftCellWrapper.RightCellQuery.Extent; // relation or extent to group by Debug.Assert(extent != null, "Each cell must have a right extent"); // Add the childNode as a child of the FOJ tree for "extent" extentMap.Add(extent, childNode); } // Now go through the extent map and create FOJ nodes for each extent // Place the nodes for that extent in the newly-created FOJ subtree // Also add the op node for every node as a child of the final result var result = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ); foreach (var extent in extentMap.Keys) { var extentFojNode = new OpCellTreeNode(m_viewgenContext, CellTreeOpType.FOJ); foreach (var childNode in extentMap.ListForKey(extent)) { extentFojNode.Add(childNode); } result.Add(extentFojNode); } // We call Flatten to remove any unnecessary nestings // where an OpNode has only 1 child. return result.Flatten(); }
// Loads and registers any function mapping translators for the given extent (and related container) private void InitializeFunctionMappingTranslators(EntitySetBase entitySetBase, EntityContainerMapping mapping) { var requiredEnds = new KeyToListMap <AssociationSet, AssociationEndMember>( EqualityComparer <AssociationSet> .Default); // see if function mapping metadata needs to be processed if (!m_functionMappingTranslators.ContainsKey(entitySetBase)) { // load all function mapping data from the current entity container foreach (EntitySetMapping entitySetMapping in mapping.EntitySetMaps) { if (0 < entitySetMapping.ModificationFunctionMappings.Count) { // register the function mapping m_functionMappingTranslators.Add( entitySetMapping.Set, ModificationFunctionMappingTranslator.CreateEntitySetTranslator(entitySetMapping)); // register "null" function translators for all implicitly mapped association sets foreach (var end in entitySetMapping.ImplicitlyMappedAssociationSetEnds) { var associationSet = end.ParentAssociationSet; if (!m_functionMappingTranslators.ContainsKey(associationSet)) { m_functionMappingTranslators.Add( associationSet, ModificationFunctionMappingTranslator.CreateAssociationSetTranslator(null)); } // Remember that the current entity set is required for all updates to the collocated // relationship set. This entity set's end is opposite the target end for the mapping. var oppositeEnd = MetadataHelper.GetOppositeEnd(end); requiredEnds.Add(associationSet, oppositeEnd.CorrespondingAssociationEndMember); } } else { // register null translator (so that we never attempt to process this extent again) m_functionMappingTranslators.Add(entitySetMapping.Set, null); } } foreach (AssociationSetMapping associationSetMapping in mapping.RelationshipSetMaps) { if (null != associationSetMapping.ModificationFunctionMapping) { var set = (AssociationSet)associationSetMapping.Set; // use indexer rather than Add since the association set may already have an implicit function // mapping -- this explicit function mapping takes precedence in such cases m_functionMappingTranslators.Add( set, ModificationFunctionMappingTranslator.CreateAssociationSetTranslator(associationSetMapping)); // remember that we've seen a function mapping for this association set, which overrides // any other behaviors for determining required/optional ends requiredEnds.AddRange(set, Enumerable.Empty <AssociationEndMember>()); } else { if (!m_functionMappingTranslators.ContainsKey(associationSetMapping.Set)) { // register null translator (so that we never attempt to process this extent again) m_functionMappingTranslators.Add(associationSetMapping.Set, null); } } } } // register association metadata for all association sets encountered foreach (var associationSet in requiredEnds.Keys) { m_associationSetMetadata.Add( associationSet, new AssociationSetMetadata( requiredEnds.EnumerateValues(associationSet))); } }
internal FunctionImportStructuralTypeMappingKB( IEnumerable <FunctionImportStructuralTypeMapping> structuralTypeMappings, ItemCollection itemCollection) { DebugCheck.NotNull(structuralTypeMappings); DebugCheck.NotNull(itemCollection); m_itemCollection = itemCollection; // If no specific type mapping. if (structuralTypeMappings.Count() == 0) { // Initialize with defaults. ReturnTypeColumnsRenameMapping = new Dictionary <string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping>(); NormalizedEntityTypeMappings = new ReadOnlyCollection <FunctionImportNormalizedEntityTypeMapping>( new List <FunctionImportNormalizedEntityTypeMapping>()); DiscriminatorColumns = new ReadOnlyCollection <string>(new List <string>()); MappedEntityTypes = new ReadOnlyCollection <EntityType>(new List <EntityType>()); return; } var entityTypeMappings = structuralTypeMappings.OfType <FunctionImportEntityTypeMapping>(); // FunctionImportEntityTypeMapping if (null != entityTypeMappings && null != entityTypeMappings.FirstOrDefault()) { var isOfTypeEntityTypeColumnsRenameMapping = new Dictionary <EntityType, Collection <FunctionImportReturnTypePropertyMapping> >(); var entityTypeColumnsRenameMapping = new Dictionary <EntityType, Collection <FunctionImportReturnTypePropertyMapping> >(); var normalizedEntityTypeMappings = new List <FunctionImportNormalizedEntityTypeMapping>(); // Collect all mapped entity types. MappedEntityTypes = entityTypeMappings .SelectMany(mapping => mapping.GetMappedEntityTypes(m_itemCollection)) .Distinct() .ToList() .AsReadOnly(); // Collect all discriminator columns. DiscriminatorColumns = entityTypeMappings .SelectMany(mapping => mapping.GetDiscriminatorColumns()) .Distinct() .ToList() .AsReadOnly(); m_entityTypeLineInfos = new KeyToListMap <EntityType, LineInfo>(EqualityComparer <EntityType> .Default); m_isTypeOfLineInfos = new KeyToListMap <EntityType, LineInfo>(EqualityComparer <EntityType> .Default); foreach (var entityTypeMapping in entityTypeMappings) { // Remember LineInfos for error reporting. foreach (var entityType in entityTypeMapping.EntityTypes) { m_entityTypeLineInfos.Add(entityType, entityTypeMapping.LineInfo); } foreach (var isTypeOf in entityTypeMapping.IsOfTypeEntityTypes) { m_isTypeOfLineInfos.Add(isTypeOf, entityTypeMapping.LineInfo); } // Create map from column name to condition. var columnMap = entityTypeMapping.Conditions.ToDictionary( condition => condition.ColumnName, condition => condition); // Align conditions with discriminator columns. var columnMappings = new List <FunctionImportEntityTypeMappingCondition>(DiscriminatorColumns.Count); for (var i = 0; i < DiscriminatorColumns.Count; i++) { var discriminatorColumn = DiscriminatorColumns[i]; FunctionImportEntityTypeMappingCondition mappingCondition; if (columnMap.TryGetValue(discriminatorColumn, out mappingCondition)) { columnMappings.Add(mappingCondition); } else { // Null indicates the value for this discriminator doesn't matter. columnMappings.Add(null); } } // Create bit map for implied entity types. var impliedEntityTypesBitMap = new bool[MappedEntityTypes.Count]; var impliedEntityTypesSet = new Set <EntityType>(entityTypeMapping.GetMappedEntityTypes(m_itemCollection)); for (var i = 0; i < MappedEntityTypes.Count; i++) { impliedEntityTypesBitMap[i] = impliedEntityTypesSet.Contains(MappedEntityTypes[i]); } // Construct normalized mapping. normalizedEntityTypeMappings.Add( new FunctionImportNormalizedEntityTypeMapping(this, columnMappings, new BitArray(impliedEntityTypesBitMap))); // Construct the rename mappings by adding isTypeOf types and specific entity types to the corresponding lists. foreach (var isOfType in entityTypeMapping.IsOfTypeEntityTypes) { if (!isOfTypeEntityTypeColumnsRenameMapping.Keys.Contains(isOfType)) { isOfTypeEntityTypeColumnsRenameMapping.Add( isOfType, new Collection <FunctionImportReturnTypePropertyMapping>()); } foreach (var rename in entityTypeMapping.ColumnsRenameList) { isOfTypeEntityTypeColumnsRenameMapping[isOfType].Add(rename); } } foreach (var entityType in entityTypeMapping.EntityTypes) { if (!entityTypeColumnsRenameMapping.Keys.Contains(entityType)) { entityTypeColumnsRenameMapping.Add(entityType, new Collection <FunctionImportReturnTypePropertyMapping>()); } foreach (var rename in entityTypeMapping.ColumnsRenameList) { entityTypeColumnsRenameMapping[entityType].Add(rename); } } } ReturnTypeColumnsRenameMapping = new FunctionImportReturnTypeEntityTypeColumnsRenameBuilder( isOfTypeEntityTypeColumnsRenameMapping, entityTypeColumnsRenameMapping) .ColumnRenameMapping; NormalizedEntityTypeMappings = new ReadOnlyCollection <FunctionImportNormalizedEntityTypeMapping>( normalizedEntityTypeMappings); } else { // FunctionImportComplexTypeMapping Debug.Assert( structuralTypeMappings.First() is FunctionImportComplexTypeMapping, "only two types can have renames, complexType and entityType"); var complexTypeMappings = structuralTypeMappings.Cast <FunctionImportComplexTypeMapping>(); Debug.Assert( complexTypeMappings.Count() == 1, "how come there are more than 1, complex type cannot derive from other complex type"); ReturnTypeColumnsRenameMapping = new Dictionary <string, FunctionImportReturnTypeStructuralTypeColumnRenameMapping>(); foreach (var rename in complexTypeMappings.First().ColumnsRenameList) { var columnRenameMapping = new FunctionImportReturnTypeStructuralTypeColumnRenameMapping(rename.CMember); columnRenameMapping.AddRename( new FunctionImportReturnTypeStructuralTypeColumn( rename.SColumn, complexTypeMappings.First().ReturnType, false, rename.LineInfo)); ReturnTypeColumnsRenameMapping.Add(rename.CMember, columnRenameMapping); } // Initialize the entity mapping data as empty. NormalizedEntityTypeMappings = new ReadOnlyCollection <FunctionImportNormalizedEntityTypeMapping>( new List <FunctionImportNormalizedEntityTypeMapping>()); DiscriminatorColumns = new ReadOnlyCollection <string>( new List <string> { }); MappedEntityTypes = new ReadOnlyCollection <EntityType>( new List <EntityType> { }); } }
// effects: A restrictive version of GroupLeafChildrenByExtent -- // only for LASJ and LOJ nodes (works for LOJ only when A LOJ B LOJ C // s.t., B and C are subsets of A -- in our case that is how LOJs are constructed private static List<CellTreeNode> GroupNonAssociativeLeafChildren(List<CellTreeNode> nodes) { // Keep track of leaf cells for each extent ignoring the 0th child KeyToListMap<EntitySetBase, CellTreeNode> extentMap = new KeyToListMap<EntitySetBase, CellTreeNode>(EqualityComparer<EntitySetBase>.Default); List<CellTreeNode> newNodes = new List<CellTreeNode>(); List<CellTreeNode> nonLeafNodes = new List<CellTreeNode>(); // Add the 0th child newNodes.Add(nodes[0]); for (int i = 1; i < nodes.Count; i++) { CellTreeNode node = nodes[i]; LeafCellTreeNode leafNode = node as LeafCellTreeNode; // All non-leaf nodes are added to the result now // leaf nodes are added outside the loop if (leafNode != null) { extentMap.Add(leafNode.LeftCellWrapper.RightCellQuery.Extent, leafNode); } else { nonLeafNodes.Add(node); } } // Go through the map and add the leaf children // If a group of nodes exists for the 0th node's extent -- place // that group first LeafCellTreeNode firstNode = nodes[0] as LeafCellTreeNode; if (firstNode != null) { EntitySetBase firstExtent = firstNode.LeftCellWrapper.RightCellQuery.Extent; if (extentMap.ContainsKey(firstExtent)) { newNodes.AddRange(extentMap.ListForKey(firstExtent)); // Remove this set from the map extentMap.RemoveKey(firstExtent); } } newNodes.AddRange(extentMap.AllValues); newNodes.AddRange(nonLeafNodes); return newNodes; }
// effects: Checks if all sViewConstraints are implied by the // constraints in cViewConstraints. If some S-level constraints are // not implied, adds errors/warnings to m_errorLog private void CheckImplication(ViewSchemaConstraints cViewConstraints, ViewSchemaConstraints sViewConstraints) { // Check key constraints // i.e., if S has a key <k1, k2>, C must have a key that is a subset of this CheckImplicationKeyConstraints(cViewConstraints, sViewConstraints); // For updates, we need to ensure the following: for every // extent E, table T pair, some key of E is implied by T's key // Get all key constraints for each extent and each table var extentPairConstraints = new KeyToListMap<ExtentPair, ViewKeyConstraint>(EqualityComparer<ExtentPair>.Default); foreach (var cKeyConstraint in cViewConstraints.KeyConstraints) { var pair = new ExtentPair(cKeyConstraint.Cell.CQuery.Extent, cKeyConstraint.Cell.SQuery.Extent); extentPairConstraints.Add(pair, cKeyConstraint); } // Now check that we guarantee at least one constraint per // extent/table pair foreach (var extentPair in extentPairConstraints.Keys) { var cKeyConstraints = extentPairConstraints.ListForKey(extentPair); var sImpliesSomeC = false; // Go through all key constraints for the extent/table pair, and find one that S implies foreach (var cKeyConstraint in cKeyConstraints) { foreach (var sKeyConstraint in sViewConstraints.KeyConstraints) { if (sKeyConstraint.Implies(cKeyConstraint)) { sImpliesSomeC = true; break; // The implication holds - so no problem } } } if (sImpliesSomeC == false) { // Indicate that at least one key must be ensured on the S-side m_errorLog.AddEntry(ViewKeyConstraint.GetErrorRecord(cKeyConstraints)); } } }
// requires: All slots in this are join tree slots // This method is called for an S-side query // cQuery is the corresponding C-side query in the cell // sourceCell is the original cell for "this" and cQuery // effects: Checks if any of the columns in "this" are mapped to multiple properties in cQuery. If so, // returns an error record about the duplicated slots internal ErrorLog.Record CheckForDuplicateFields(CellQuery cQuery, Cell sourceCell) { // slotMap stores the slots on the S-side and the // C-side properties that it maps to var slotMap = new KeyToListMap<MemberProjectedSlot, int>(ProjectedSlot.EqualityComparer); // Note that this does work for self-association. In the manager // employee example, ManagerId and EmployeeId from the SEmployee // table map to the two ends -- Manager.ManagerId and // Employee.EmployeeId in the C Space for (var i = 0; i < m_projectedSlots.Length; i++) { var projectedSlot = m_projectedSlots[i]; var slot = projectedSlot as MemberProjectedSlot; Debug.Assert(slot != null, "All slots for this method must be JoinTreeSlots"); slotMap.Add(slot, i); } StringBuilder builder = null; // Now determine the entries that have more than one integer per slot var isErrorSituation = false; foreach (var slot in slotMap.Keys) { var indexes = slotMap.ListForKey(slot); Debug.Assert(indexes.Count >= 1, "Each slot must have one index at least"); if (indexes.Count > 1 && cQuery.AreSlotsEquivalentViaRefConstraints(indexes) == false) { // The column is mapped to more than one property and it // failed the "association corresponds to referential // constraints" check isErrorSituation = true; if (builder == null) { builder = new StringBuilder(Strings.ViewGen_Duplicate_CProperties(Extent.Name)); builder.AppendLine(); } var tmpBuilder = new StringBuilder(); for (var i = 0; i < indexes.Count; i++) { var index = indexes[i]; if (i != 0) { tmpBuilder.Append(", "); } // The slot must be a JoinTreeSlot. If it isn't it is an internal error var cSlot = (MemberProjectedSlot)cQuery.m_projectedSlots[index]; tmpBuilder.Append(cSlot.ToUserString()); } builder.AppendLine(Strings.ViewGen_Duplicate_CProperties_IsMapped(slot.ToUserString(), tmpBuilder.ToString())); } } if (false == isErrorSituation) { return null; } var record = new ErrorLog.Record(ViewGenErrorCode.DuplicateCPropertiesMapped, builder.ToString(), sourceCell, String.Empty); return record; }
// effects: Given a list of node, produces a new list in which all // leaf nodes of the same extent are adjacent to each other. Non-leaf // nodes are also adjacent to each other. CHANGE_[....]_IMPROVE: Merge with GroupByRightExtent private static List<CellTreeNode> GroupLeafChildrenByExtent(List<CellTreeNode> nodes) { // Keep track of leaf cells for each extent KeyToListMap<EntitySetBase, CellTreeNode> extentMap = new KeyToListMap<EntitySetBase, CellTreeNode>(EqualityComparer<EntitySetBase>.Default); List<CellTreeNode> newNodes = new List<CellTreeNode>(); foreach (CellTreeNode node in nodes) { LeafCellTreeNode leafNode = node as LeafCellTreeNode; // All non-leaf nodes are added to the result now // leaf nodes are added outside the loop if (leafNode != null) { extentMap.Add(leafNode.LeftCellWrapper.RightCellQuery.Extent, leafNode); } else { newNodes.Add(node); } } // Go through the map and add the leaf children newNodes.AddRange(extentMap.AllValues); return newNodes; }