private void AddModelDependencies( KeyToListMap <EntityKey, UpdateCommand> producedMap, KeyToListMap <EntityKey, UpdateCommand> requiredMap) { foreach (var keyAndCommands in requiredMap.KeyValuePairs) { var key = keyAndCommands.Key; var commandsRequiringKey = keyAndCommands.Value; foreach (var commandProducingKey in producedMap.EnumerateValues(key)) { foreach (var commandRequiringKey in commandsRequiringKey) { // command cannot depend on itself and only function commands // need to worry about model dependencies (dynamic commands know about foreign keys) if (!ReferenceEquals(commandProducingKey, commandRequiringKey) && (commandProducingKey.Kind == UpdateCommandKind.Function || commandRequiringKey.Kind == UpdateCommandKind.Function)) { // add a dependency AddEdge(commandProducingKey, commandRequiringKey); } } } } }
private void CollectUnreachableTypes(Set <EntityType> reachableTypes, out KeyToListMap <EntityType, LineInfo> entityTypes, out KeyToListMap <EntityType, LineInfo> isTypeOfEntityTypes) { // Collect line infos for types in violation entityTypes = new KeyToListMap <EntityType, LineInfo>(EqualityComparer <EntityType> .Default); isTypeOfEntityTypes = new KeyToListMap <EntityType, LineInfo>(EqualityComparer <EntityType> .Default); if (reachableTypes.Count == this.MappedEntityTypes.Count) { // All types are reachable; nothing to check return; } // Find IsTypeOf mappings where no type in hierarchy can generate a row foreach (var isTypeOf in m_isTypeOfLineInfos.Keys) { if (!MetadataHelper.GetTypeAndSubtypesOf(isTypeOf, m_itemCollection, false) .Cast <EntityType>() .Intersect(reachableTypes) .Any()) { // no type in the hierarchy is reachable... isTypeOfEntityTypes.AddRange(isTypeOf, m_isTypeOfLineInfos.EnumerateValues(isTypeOf)); } } // Find explicit types not generating a value foreach (var entityType in m_entityTypeLineInfos.Keys) { if (!reachableTypes.Contains(entityType)) { entityTypes.AddRange(entityType, m_entityTypeLineInfos.EnumerateValues(entityType)); } } }
private void AddForeignKeyEdges( KeyToListMap <UpdateCommandOrderer.ForeignKeyValue, UpdateCommand> predecessors) { foreach (DynamicUpdateCommand dynamicUpdateCommand in this.Vertices.OfType <DynamicUpdateCommand>()) { if (dynamicUpdateCommand.Operator == ModificationOperator.Update || ModificationOperator.Insert == dynamicUpdateCommand.Operator) { foreach (ReferentialConstraint enumerateValue1 in this._sourceMap.EnumerateValues((EntitySetBase)dynamicUpdateCommand.Table)) { UpdateCommandOrderer.ForeignKeyValue key1; UpdateCommandOrderer.ForeignKeyValue key2; if (UpdateCommandOrderer.ForeignKeyValue.TryCreateSourceKey(enumerateValue1, dynamicUpdateCommand.CurrentValues, true, out key1) && (dynamicUpdateCommand.Operator != ModificationOperator.Update || !UpdateCommandOrderer.ForeignKeyValue.TryCreateSourceKey(enumerateValue1, dynamicUpdateCommand.OriginalValues, true, out key2) || !this._keyComparer.Equals(key2, key1))) { foreach (UpdateCommand enumerateValue2 in predecessors.EnumerateValues(key1)) { if (enumerateValue2 != dynamicUpdateCommand) { this.AddEdge(enumerateValue2, (UpdateCommand)dynamicUpdateCommand); } } } } } if (dynamicUpdateCommand.Operator == ModificationOperator.Update || ModificationOperator.Delete == dynamicUpdateCommand.Operator) { foreach (ReferentialConstraint enumerateValue1 in this._targetMap.EnumerateValues((EntitySetBase)dynamicUpdateCommand.Table)) { UpdateCommandOrderer.ForeignKeyValue key1; UpdateCommandOrderer.ForeignKeyValue key2; if (UpdateCommandOrderer.ForeignKeyValue.TryCreateTargetKey(enumerateValue1, dynamicUpdateCommand.OriginalValues, false, out key1) && (dynamicUpdateCommand.Operator != ModificationOperator.Update || !UpdateCommandOrderer.ForeignKeyValue.TryCreateTargetKey(enumerateValue1, dynamicUpdateCommand.CurrentValues, false, out key2) || !this._keyComparer.Equals(key2, key1))) { foreach (UpdateCommand enumerateValue2 in predecessors.EnumerateValues(key1)) { if (enumerateValue2 != dynamicUpdateCommand) { this.AddEdge(enumerateValue2, (UpdateCommand)dynamicUpdateCommand); } } } } } } }
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))); } }
private void AddModelDependencies( KeyToListMap <EntityKey, UpdateCommand> producedMap, KeyToListMap <EntityKey, UpdateCommand> requiredMap) { foreach (KeyValuePair <EntityKey, List <UpdateCommand> > keyValuePair in requiredMap.KeyValuePairs) { EntityKey key = keyValuePair.Key; List <UpdateCommand> updateCommandList = keyValuePair.Value; foreach (UpdateCommand enumerateValue in producedMap.EnumerateValues(key)) { foreach (UpdateCommand to in updateCommandList) { if (!object.ReferenceEquals((object)enumerateValue, (object)to) && (enumerateValue.Kind == UpdateCommandKind.Function || to.Kind == UpdateCommandKind.Function)) { this.AddEdge(enumerateValue, to); } } } } }
// 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))); } }
// Finds all successors to the given predecessors and registers the resulting dependency edges in this // graph. // // - Commands (updates or inserts) inserting FK "sources" (referencing foreign key) // - Commands (updates or deletes) deleting FK "targets" (referenced by the foreign key) // // To avoid violating constraints, FK references must be created before their referees, and // cannot be deleted before their references. private void AddForeignKeyEdges(KeyToListMap <ForeignKeyValue, UpdateCommand> predecessors) { foreach (var command in Vertices.OfType <DynamicUpdateCommand>()) { // register all source successors if (ModificationOperator.Update == command.Operator || ModificationOperator.Insert == command.Operator) { foreach (var fkConstraint in _sourceMap.EnumerateValues(command.Table)) { ForeignKeyValue fk; if (ForeignKeyValue.TryCreateSourceKey(fkConstraint, command.CurrentValues, true, 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 target, the update // is a no-op) ForeignKeyValue originalFK; if (ModificationOperator.Update != command.Operator || !ForeignKeyValue.TryCreateSourceKey(fkConstraint, command.OriginalValues, true, out originalFK) || !_keyComparer.Equals(originalFK, fk)) { foreach (var predecessor in predecessors.EnumerateValues(fk)) { // don't add self-edges for FK dependencies, since a single operation // in the store is atomic if (predecessor != command) { AddEdge(predecessor, command); } } } } } } // register all target successors if (ModificationOperator.Update == command.Operator || ModificationOperator.Delete == command.Operator) { foreach (var fkConstraint in _targetMap.EnumerateValues(command.Table)) { ForeignKeyValue fk; if (ForeignKeyValue.TryCreateTargetKey(fkConstraint, command.OriginalValues, false, 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 source, the update // is a no-op) ForeignKeyValue currentFK; if (ModificationOperator.Update != command.Operator || !ForeignKeyValue.TryCreateTargetKey(fkConstraint, command.CurrentValues, false, out currentFK) || !_keyComparer.Equals(currentFK, fk)) { foreach (var predecessor in predecessors.EnumerateValues(fk)) { // don't add self-edges for FK dependencies, since a single operation // in the store is atomic if (predecessor != command) { AddEdge(predecessor, command); } } } } } } } }