Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / updatecommandorderer.cs / 1 / 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 (Int64 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 (Int64 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() { // build up 'required' and 'producing' graphs KeyToListMaprequiredMap = new KeyToListMap (EqualityComparer .Default); KeyToListMap producedMap = new KeyToListMap (EqualityComparer .Default); foreach (UpdateCommand command in this.Vertices) { List required; List produced; command.GetRequiredAndProducedEntities(_translator, out required, out produced); foreach (EntityKey key in required) { requiredMap.Add(key, command); } foreach (EntityKey key in produced) { producedMap.Add(key, command); } } // build up dependencies 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 (Int64 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 (Int64 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() { // build up 'required' and 'producing' graphs KeyToListMaprequiredMap = new KeyToListMap (EqualityComparer .Default); KeyToListMap producedMap = new KeyToListMap (EqualityComparer .Default); foreach (UpdateCommand command in this.Vertices) { List required; List produced; command.GetRequiredAndProducedEntities(_translator, out required, out produced); foreach (EntityKey key in required) { requiredMap.Add(key, command); } foreach (EntityKey key in produced) { producedMap.Add(key, command); } } // build up dependencies 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
- ParenthesizePropertyNameAttribute.cs
- AsymmetricKeyExchangeFormatter.cs
- SelfIssuedAuthRSACryptoProvider.cs
- MatrixTransform3D.cs
- Compilation.cs
- TemplatePropertyEntry.cs
- Int32KeyFrameCollection.cs
- PersonalizationAdministration.cs
- ByteStorage.cs
- UseAttributeSetsAction.cs
- AutomationPeer.cs
- UIElementHelper.cs
- ChannelCredentials.cs
- MessageDroppedTraceRecord.cs
- RegexStringValidatorAttribute.cs
- GroupBox.cs
- XamlTypeWithExplicitNamespace.cs
- ContentPlaceHolderDesigner.cs
- InputDevice.cs
- MdbDataFileEditor.cs
- GeneralTransform3D.cs
- FixedSOMLineCollection.cs
- RegistrationServices.cs
- ValidatingReaderNodeData.cs
- StandardBindingReliableSessionElement.cs
- ManagementOptions.cs
- TreeNodeMouseHoverEvent.cs
- SqlInternalConnectionTds.cs
- Compiler.cs
- BaseProcessor.cs
- GuidConverter.cs
- ReadContentAsBinaryHelper.cs
- XmlCompatibilityReader.cs
- WriteStateInfoBase.cs
- Attributes.cs
- Bidi.cs
- EmulateRecognizeCompletedEventArgs.cs
- FixedSOMPageConstructor.cs
- TrailingSpaceComparer.cs
- MulticastDelegate.cs
- NamedPermissionSet.cs
- RegexWorker.cs
- SQLByteStorage.cs
- PresentationTraceSources.cs
- TCEAdapterGenerator.cs
- ProcessHost.cs
- TextEndOfLine.cs
- COM2FontConverter.cs
- __ConsoleStream.cs
- TreeNodeBinding.cs
- BuildManagerHost.cs
- GridViewColumn.cs
- DriveInfo.cs
- TextEndOfParagraph.cs
- MediaEntryAttribute.cs
- MouseCaptureWithinProperty.cs
- UpdateExpressionVisitor.cs
- WindowsScrollBarBits.cs
- EmptyCollection.cs
- ContainerParagraph.cs
- PassportAuthenticationModule.cs
- TransactionOptions.cs
- WindowsAltTab.cs
- JsonGlobals.cs
- TaskCanceledException.cs
- FilterableData.cs
- WebPartVerbsEventArgs.cs
- DateBoldEvent.cs
- KeySpline.cs
- RtfToXamlReader.cs
- ToggleButton.cs
- MarshalByRefObject.cs
- KeyPullup.cs
- MobileControlsSection.cs
- HwndKeyboardInputProvider.cs
- CodeExporter.cs
- DesignerDataSourceView.cs
- AutomationAttributeInfo.cs
- QueryGeneratorBase.cs
- SafeEventLogWriteHandle.cs
- ConfigurationCollectionAttribute.cs
- Misc.cs
- BaseCAMarshaler.cs
- DataGridViewRowStateChangedEventArgs.cs
- SiteMapHierarchicalDataSourceView.cs
- ReflectPropertyDescriptor.cs
- SharedDp.cs
- SqlCacheDependencyDatabaseCollection.cs
- PenThreadPool.cs
- InvalidFilterCriteriaException.cs
- MergePropertyDescriptor.cs
- FrameworkReadOnlyPropertyMetadata.cs
- IdentityReference.cs
- DataControlReference.cs
- SqlDataSourceCommandEventArgs.cs
- ControlEvent.cs
- GeneralTransform3D.cs
- TextClipboardData.cs
- SqlXmlStorage.cs
- Effect.cs