Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / updatecommandorderer.cs / 1305376 / updatecommandorderer.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Collections.Generic; using System.Data.Common.Utils; using System.Data.Metadata.Edm; using System.Linq; using System.Diagnostics; namespace System.Data.Mapping.Update.Internal { internal class UpdateCommandOrderer : Graph{ /// /// Gets comparer used to resolve identifiers to actual 'owning' key values (e.g. across referential constraints) /// private readonly ForeignKeyValueComparer _keyComparer; ////// Maps from tables to all "source" referential constraints (where the table declares /// foreign keys) /// private readonly KeyToListMap_sourceMap; /// /// Maps from tables to all "target" referential constraints (where the table is /// referenced by a foreign key) /// private readonly KeyToListMap_targetMap; /// /// Tracks whether any function commands exist in the current payload. /// private readonly bool _hasFunctionCommands; ////// Gets translator producing this graph. /// private readonly UpdateTranslator _translator; internal UpdateCommandOrderer(IEnumerablecommands, UpdateTranslator translator) : base(EqualityComparer .Default) { _translator = translator; _keyComparer = new ForeignKeyValueComparer(_translator.KeyComparer); HashSet tables = new HashSet (); HashSet containers = new HashSet (); // add all vertices (one vertex for every command) foreach (UpdateCommand command in commands) { if (null != command.Table) { tables.Add(command.Table); containers.Add(command.Table.EntityContainer); } AddVertex(command); if (command.Kind == UpdateCommandKind.Function) { _hasFunctionCommands = true; } } // figure out which foreign keys are interesting in this scope InitializeForeignKeyMaps(containers, tables, out _sourceMap, out _targetMap); // add edges for each ordering dependency amongst the commands AddServerGenDependencies(); AddForeignKeyDependencies(); if (_hasFunctionCommands) { AddModelDependencies(); } } private static void InitializeForeignKeyMaps(HashSet containers, HashSet tables, out KeyToListMap sourceMap, out KeyToListMap targetMap) { sourceMap = new KeyToListMap (EqualityComparer .Default); targetMap = new KeyToListMap (EqualityComparer .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); } } } } } } } // Adds edges to dependency graph for server-generated values. // // Determines which commands produce identifiers (key components) and which commands // consume them. Producers are potentially edge predecessors and consumers are potentially // edge successors. The command objects report the identifiers they produce (OutputIdentifiers) // and the identifiers they consume (InputIdentifiers) private void AddServerGenDependencies() { // Identify all "shared" output parameters (e.g., SQL Server identifiers) Dictionary predecessors = new Dictionary (); foreach (UpdateCommand command in this.Vertices) { foreach (int output in command.OutputIdentifiers) { try { predecessors.Add(output, command); } catch (ArgumentException duplicateKey) { // throw an exception indicating that a key value is generated in two locations // in the store throw EntityUtil.Update(System.Data.Entity.Strings.Update_AmbiguousServerGenIdentifier, duplicateKey, command.GetStateEntries(_translator)); } } } // Identify all dependent input parameters foreach (UpdateCommand command in this.Vertices) { foreach (int input in command.InputIdentifiers) { UpdateCommand from; if (predecessors.TryGetValue(input, out from)) { AddEdge(from, command); } } } } // Adds edges to dependency graph based on foreign keys. private void AddForeignKeyDependencies() { KeyToListMap predecessors = DetermineForeignKeyPredecessors(); AddForeignKeyEdges(predecessors); } // 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 predecessors) { foreach (DynamicUpdateCommand command in this.Vertices.OfType ()) { // register all source successors if (ModificationOperator.Update == command.Operator || ModificationOperator.Insert == command.Operator) { foreach (ReferentialConstraint 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 (UpdateCommand 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 (ReferentialConstraint 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 (UpdateCommand 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); } } } } } } } } // 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 DetermineForeignKeyPredecessors() { KeyToListMap predecessors = new KeyToListMap ( _keyComparer); foreach (DynamicUpdateCommand command in this.Vertices.OfType ()) { if (ModificationOperator.Update == command.Operator || ModificationOperator.Insert == command.Operator) { foreach (ReferentialConstraint 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 (ReferentialConstraint 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; } /// /// For function commands, we infer constraints based on relationships and entities. For instance, /// we always insert an entity before inserting a relationship referencing that entity. When dynamic /// and function UpdateCommands are mixed, we also fall back on this same interpretation. /// private void AddModelDependencies() { KeyToListMapaddedEntities = new KeyToListMap (EqualityComparer .Default); KeyToListMap deletedEntities = new KeyToListMap (EqualityComparer .Default); KeyToListMap addedRelationships = new KeyToListMap (EqualityComparer .Default); KeyToListMap deletedRelationships = new KeyToListMap (EqualityComparer .Default); foreach (UpdateCommand command in this.Vertices) { command.GetRequiredAndProducedEntities(_translator, addedEntities, deletedEntities, addedRelationships, deletedRelationships); } // Add entities before adding dependent relationships AddModelDependencies(producedMap: addedEntities, requiredMap: addedRelationships); // Delete dependent relationships before deleting entities AddModelDependencies(producedMap: deletedRelationships, requiredMap: deletedEntities); } private void AddModelDependencies(KeyToListMap producedMap, KeyToListMap requiredMap) { foreach (var keyAndCommands in requiredMap.KeyValuePairs) { EntityKey key = keyAndCommands.Key; List commandsRequiringKey = keyAndCommands.Value; foreach (UpdateCommand commandProducingKey in producedMap.EnumerateValues(key)) { foreach (UpdateCommand 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 (!object.ReferenceEquals(commandProducingKey, commandRequiringKey) && (commandProducingKey.Kind == UpdateCommandKind.Function || commandRequiringKey.Kind == UpdateCommandKind.Function)) { // add a dependency AddEdge(commandProducingKey, commandRequiringKey); } } } } } /// /// Describes an update command's foreign key (source or target) /// private struct ForeignKeyValue { ////// Constructor /// /// Sets Metadata /// Record containing key value /// Indicates whether the source or target end of the constraint /// is being pulled /// Indicates whether this is an insert dependency or a delete /// dependency private ForeignKeyValue(ReferentialConstraint metadata, PropagatorResult record, bool isTarget, bool isInsert) { Metadata = metadata; // construct key IListkeyProperties = isTarget ? metadata.FromProperties : metadata.ToProperties; PropagatorResult[] keyValues = new PropagatorResult[keyProperties.Count]; bool hasNullMember = false; for (int i = 0; i < keyValues.Length; i++) { keyValues[i] = record.GetMemberValue(keyProperties[i]); if (keyValues[i].IsNull) { hasNullMember = true; break; } } if (hasNullMember) { // set key to null to indicate that it is not behaving as a key // (in SQL, keys with null components do not participate in constraints) Key = null; } else { Key = new CompositeKey(keyValues); } IsInsert = isInsert; } /// /// Initialize foreign key object for the target of a foreign key. /// /// Sets Metadata /// Record containing key value /// Indicates whether the key value is being inserted or deleted /// Outputs key object ///true if the record contains key values for this constraint; false otherwise internal static bool TryCreateTargetKey(ReferentialConstraint metadata, PropagatorResult record, bool isInsert, out ForeignKeyValue key) { key = new ForeignKeyValue(metadata, record, true, isInsert); if (null == key.Key) { return false; } return true; } ////// Initialize foreign key object for the source of a foreign key. /// /// Sets Metadata /// Record containing key value /// Indicates whether the key value is being inserted or deleted /// Outputs key object ///true if the record contains key values for this constraint; false otherwise internal static bool TryCreateSourceKey(ReferentialConstraint metadata, PropagatorResult record, bool isInsert, out ForeignKeyValue key) { key = new ForeignKeyValue(metadata, record, false, isInsert); if (null == key.Key) { return false; } return true; } ////// Foreign key metadata. /// internal readonly ReferentialConstraint Metadata; ////// Foreign key value. /// internal readonly CompositeKey Key; ////// Indicates whether this is an inserted or deleted key value. /// internal readonly bool IsInsert; } ////// Equality comparer for ForeignKey class. /// private class ForeignKeyValueComparer : IEqualityComparer{ private readonly IEqualityComparer _baseComparer; internal ForeignKeyValueComparer(IEqualityComparer baseComparer) { _baseComparer = EntityUtil.CheckArgumentNull(baseComparer, "baseComparer"); } public bool Equals(ForeignKeyValue x, ForeignKeyValue y) { return x.IsInsert == y.IsInsert && x.Metadata == y.Metadata && _baseComparer.Equals(x.Key, y.Key); } public int GetHashCode(ForeignKeyValue obj) { return _baseComparer.GetHashCode(obj.Key); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Collections.Generic; using System.Data.Common.Utils; using System.Data.Metadata.Edm; using System.Linq; using System.Diagnostics; namespace System.Data.Mapping.Update.Internal { internal class UpdateCommandOrderer : Graph{ /// /// Gets comparer used to resolve identifiers to actual 'owning' key values (e.g. across referential constraints) /// private readonly ForeignKeyValueComparer _keyComparer; ////// Maps from tables to all "source" referential constraints (where the table declares /// foreign keys) /// private readonly KeyToListMap_sourceMap; /// /// Maps from tables to all "target" referential constraints (where the table is /// referenced by a foreign key) /// private readonly KeyToListMap_targetMap; /// /// Tracks whether any function commands exist in the current payload. /// private readonly bool _hasFunctionCommands; ////// Gets translator producing this graph. /// private readonly UpdateTranslator _translator; internal UpdateCommandOrderer(IEnumerablecommands, UpdateTranslator translator) : base(EqualityComparer .Default) { _translator = translator; _keyComparer = new ForeignKeyValueComparer(_translator.KeyComparer); HashSet tables = new HashSet (); HashSet containers = new HashSet (); // add all vertices (one vertex for every command) foreach (UpdateCommand command in commands) { if (null != command.Table) { tables.Add(command.Table); containers.Add(command.Table.EntityContainer); } AddVertex(command); if (command.Kind == UpdateCommandKind.Function) { _hasFunctionCommands = true; } } // figure out which foreign keys are interesting in this scope InitializeForeignKeyMaps(containers, tables, out _sourceMap, out _targetMap); // add edges for each ordering dependency amongst the commands AddServerGenDependencies(); AddForeignKeyDependencies(); if (_hasFunctionCommands) { AddModelDependencies(); } } private static void InitializeForeignKeyMaps(HashSet containers, HashSet tables, out KeyToListMap sourceMap, out KeyToListMap targetMap) { sourceMap = new KeyToListMap (EqualityComparer .Default); targetMap = new KeyToListMap (EqualityComparer .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); } } } } } } } // Adds edges to dependency graph for server-generated values. // // Determines which commands produce identifiers (key components) and which commands // consume them. Producers are potentially edge predecessors and consumers are potentially // edge successors. The command objects report the identifiers they produce (OutputIdentifiers) // and the identifiers they consume (InputIdentifiers) private void AddServerGenDependencies() { // Identify all "shared" output parameters (e.g., SQL Server identifiers) Dictionary predecessors = new Dictionary (); foreach (UpdateCommand command in this.Vertices) { foreach (int output in command.OutputIdentifiers) { try { predecessors.Add(output, command); } catch (ArgumentException duplicateKey) { // throw an exception indicating that a key value is generated in two locations // in the store throw EntityUtil.Update(System.Data.Entity.Strings.Update_AmbiguousServerGenIdentifier, duplicateKey, command.GetStateEntries(_translator)); } } } // Identify all dependent input parameters foreach (UpdateCommand command in this.Vertices) { foreach (int input in command.InputIdentifiers) { UpdateCommand from; if (predecessors.TryGetValue(input, out from)) { AddEdge(from, command); } } } } // Adds edges to dependency graph based on foreign keys. private void AddForeignKeyDependencies() { KeyToListMap predecessors = DetermineForeignKeyPredecessors(); AddForeignKeyEdges(predecessors); } // 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 predecessors) { foreach (DynamicUpdateCommand command in this.Vertices.OfType ()) { // register all source successors if (ModificationOperator.Update == command.Operator || ModificationOperator.Insert == command.Operator) { foreach (ReferentialConstraint 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 (UpdateCommand 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 (ReferentialConstraint 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 (UpdateCommand 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); } } } } } } } } // 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 DetermineForeignKeyPredecessors() { KeyToListMap predecessors = new KeyToListMap ( _keyComparer); foreach (DynamicUpdateCommand command in this.Vertices.OfType ()) { if (ModificationOperator.Update == command.Operator || ModificationOperator.Insert == command.Operator) { foreach (ReferentialConstraint 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 (ReferentialConstraint 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; } /// /// For function commands, we infer constraints based on relationships and entities. For instance, /// we always insert an entity before inserting a relationship referencing that entity. When dynamic /// and function UpdateCommands are mixed, we also fall back on this same interpretation. /// private void AddModelDependencies() { KeyToListMapaddedEntities = new KeyToListMap (EqualityComparer .Default); KeyToListMap deletedEntities = new KeyToListMap (EqualityComparer .Default); KeyToListMap addedRelationships = new KeyToListMap (EqualityComparer .Default); KeyToListMap deletedRelationships = new KeyToListMap (EqualityComparer .Default); foreach (UpdateCommand command in this.Vertices) { command.GetRequiredAndProducedEntities(_translator, addedEntities, deletedEntities, addedRelationships, deletedRelationships); } // Add entities before adding dependent relationships AddModelDependencies(producedMap: addedEntities, requiredMap: addedRelationships); // Delete dependent relationships before deleting entities AddModelDependencies(producedMap: deletedRelationships, requiredMap: deletedEntities); } private void AddModelDependencies(KeyToListMap producedMap, KeyToListMap requiredMap) { foreach (var keyAndCommands in requiredMap.KeyValuePairs) { EntityKey key = keyAndCommands.Key; List commandsRequiringKey = keyAndCommands.Value; foreach (UpdateCommand commandProducingKey in producedMap.EnumerateValues(key)) { foreach (UpdateCommand 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 (!object.ReferenceEquals(commandProducingKey, commandRequiringKey) && (commandProducingKey.Kind == UpdateCommandKind.Function || commandRequiringKey.Kind == UpdateCommandKind.Function)) { // add a dependency AddEdge(commandProducingKey, commandRequiringKey); } } } } } /// /// Describes an update command's foreign key (source or target) /// private struct ForeignKeyValue { ////// Constructor /// /// Sets Metadata /// Record containing key value /// Indicates whether the source or target end of the constraint /// is being pulled /// Indicates whether this is an insert dependency or a delete /// dependency private ForeignKeyValue(ReferentialConstraint metadata, PropagatorResult record, bool isTarget, bool isInsert) { Metadata = metadata; // construct key IListkeyProperties = isTarget ? metadata.FromProperties : metadata.ToProperties; PropagatorResult[] keyValues = new PropagatorResult[keyProperties.Count]; bool hasNullMember = false; for (int i = 0; i < keyValues.Length; i++) { keyValues[i] = record.GetMemberValue(keyProperties[i]); if (keyValues[i].IsNull) { hasNullMember = true; break; } } if (hasNullMember) { // set key to null to indicate that it is not behaving as a key // (in SQL, keys with null components do not participate in constraints) Key = null; } else { Key = new CompositeKey(keyValues); } IsInsert = isInsert; } /// /// Initialize foreign key object for the target of a foreign key. /// /// Sets Metadata /// Record containing key value /// Indicates whether the key value is being inserted or deleted /// Outputs key object ///true if the record contains key values for this constraint; false otherwise internal static bool TryCreateTargetKey(ReferentialConstraint metadata, PropagatorResult record, bool isInsert, out ForeignKeyValue key) { key = new ForeignKeyValue(metadata, record, true, isInsert); if (null == key.Key) { return false; } return true; } ////// Initialize foreign key object for the source of a foreign key. /// /// Sets Metadata /// Record containing key value /// Indicates whether the key value is being inserted or deleted /// Outputs key object ///true if the record contains key values for this constraint; false otherwise internal static bool TryCreateSourceKey(ReferentialConstraint metadata, PropagatorResult record, bool isInsert, out ForeignKeyValue key) { key = new ForeignKeyValue(metadata, record, false, isInsert); if (null == key.Key) { return false; } return true; } ////// Foreign key metadata. /// internal readonly ReferentialConstraint Metadata; ////// Foreign key value. /// internal readonly CompositeKey Key; ////// Indicates whether this is an inserted or deleted key value. /// internal readonly bool IsInsert; } ////// Equality comparer for ForeignKey class. /// private class ForeignKeyValueComparer : IEqualityComparer{ private readonly IEqualityComparer _baseComparer; internal ForeignKeyValueComparer(IEqualityComparer baseComparer) { _baseComparer = EntityUtil.CheckArgumentNull(baseComparer, "baseComparer"); } public bool Equals(ForeignKeyValue x, ForeignKeyValue y) { return x.IsInsert == y.IsInsert && x.Metadata == y.Metadata && _baseComparer.Equals(x.Key, y.Key); } public int GetHashCode(ForeignKeyValue obj) { return _baseComparer.GetHashCode(obj.Key); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SQLSingleStorage.cs
- GradientBrush.cs
- DataServiceHostFactory.cs
- TransportElement.cs
- FixedSOMFixedBlock.cs
- SimpleFileLog.cs
- Size3D.cs
- ListBox.cs
- WebBrowserPermission.cs
- DockPattern.cs
- BindingOperations.cs
- Rethrow.cs
- SourceExpressionException.cs
- ThreadStaticAttribute.cs
- BaseParser.cs
- UserNameSecurityToken.cs
- IPHostEntry.cs
- Serializer.cs
- MemoryPressure.cs
- NativeMsmqMessage.cs
- NumericUpDownAcceleration.cs
- MessageFilter.cs
- ItemCheckedEvent.cs
- PointCollectionConverter.cs
- VarRefManager.cs
- XmlCharCheckingReader.cs
- ClientData.cs
- StringFreezingAttribute.cs
- TypedDataSetSchemaImporterExtension.cs
- InternalBufferOverflowException.cs
- SimpleHandlerFactory.cs
- RenderData.cs
- SigningDialog.cs
- externdll.cs
- TextLine.cs
- MessageQueueConverter.cs
- IWorkflowDebuggerService.cs
- InstanceCreationEditor.cs
- CapabilitiesRule.cs
- WaitHandle.cs
- SqlCommandSet.cs
- OdbcConnectionPoolProviderInfo.cs
- FieldToken.cs
- ControlIdConverter.cs
- CurrentChangingEventManager.cs
- ViewGenerator.cs
- sqlpipe.cs
- ProfileProvider.cs
- NonVisualControlAttribute.cs
- DragEvent.cs
- Button.cs
- CustomWebEventKey.cs
- DataGridViewCellLinkedList.cs
- ProviderIncompatibleException.cs
- DesignSurfaceCollection.cs
- FileSecurity.cs
- XhtmlBasicPanelAdapter.cs
- XmlSchemaGroup.cs
- AppDomainFactory.cs
- SendDesigner.xaml.cs
- datacache.cs
- Soap.cs
- ScriptComponentDescriptor.cs
- DataServiceExpressionVisitor.cs
- ImageListUtils.cs
- DataTemplateKey.cs
- SectionXmlInfo.cs
- CurrentChangingEventManager.cs
- UIHelper.cs
- HtmlInputHidden.cs
- HttpResponseHeader.cs
- DesignerProperties.cs
- FileDialogPermission.cs
- MarkupCompilePass2.cs
- XmlSchemaSimpleContent.cs
- MouseButtonEventArgs.cs
- ErrorEventArgs.cs
- TextDecorationCollection.cs
- MessageEncoderFactory.cs
- SettingsBindableAttribute.cs
- ZipIOLocalFileHeader.cs
- NonceCache.cs
- ByteConverter.cs
- RectKeyFrameCollection.cs
- WindowsProgressbar.cs
- PowerStatus.cs
- ObjectDataSource.cs
- ByteStorage.cs
- RuleInfoComparer.cs
- OleAutBinder.cs
- RangeBase.cs
- ExpandableObjectConverter.cs
- TextEffect.cs
- ClientEventManager.cs
- PartitionResolver.cs
- FontStretch.cs
- AttributeEmitter.cs
- sqlnorm.cs
- TemplateParser.cs
- Errors.cs