Code:
/ 4.0 / 4.0 / untmp / 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MemoryRecordBuffer.cs
- XmlObjectSerializerContext.cs
- DataGridViewCellStyleConverter.cs
- WebReferencesBuildProvider.cs
- DefaultSerializationProviderAttribute.cs
- XPathDocumentNavigator.cs
- CodeDefaultValueExpression.cs
- TableNameAttribute.cs
- BoundingRectTracker.cs
- IssuedTokenClientElement.cs
- CollectionContainer.cs
- QilSortKey.cs
- PbrsForward.cs
- CryptographicAttribute.cs
- LocatorPartList.cs
- ControlParser.cs
- SystemPens.cs
- DateTimeFormatInfoScanner.cs
- StorageEntitySetMapping.cs
- Matrix3DValueSerializer.cs
- ReversePositionQuery.cs
- SqlCommand.cs
- SHA1CryptoServiceProvider.cs
- SynchronizedPool.cs
- DefaultCommandConverter.cs
- MSAAEventDispatcher.cs
- BasicExpressionVisitor.cs
- UrlRoutingModule.cs
- SslStream.cs
- WorkflowApplicationEventArgs.cs
- AtomPub10CategoriesDocumentFormatter.cs
- XmlLanguageConverter.cs
- SamlSecurityTokenAuthenticator.cs
- MatrixCamera.cs
- UserNameSecurityTokenProvider.cs
- ButtonStandardAdapter.cs
- DataGridViewLayoutData.cs
- TextBox.cs
- EntityDataReader.cs
- CommandDevice.cs
- Throw.cs
- Filter.cs
- hresults.cs
- SpeechDetectedEventArgs.cs
- EntitySqlQueryCacheEntry.cs
- XmlDataSource.cs
- FileSecurity.cs
- WebPartConnectionsConnectVerb.cs
- AppDomainUnloadedException.cs
- ApplicationInfo.cs
- SQLRoleProvider.cs
- ServiceModelEnumValidatorAttribute.cs
- followingquery.cs
- ObjectDataSourceView.cs
- DataColumn.cs
- TextFragmentEngine.cs
- ThreadAbortException.cs
- Win32.cs
- ErrorTolerantObjectWriter.cs
- FindCriteriaElement.cs
- XMLUtil.cs
- LinkTarget.cs
- MailAddress.cs
- PhysicalFontFamily.cs
- TypeLibraryHelper.cs
- IssuedTokenClientElement.cs
- ForeignKeyFactory.cs
- RuntimeHelpers.cs
- SizeAnimationClockResource.cs
- ServiceObjectContainer.cs
- SafeBuffer.cs
- Rect.cs
- NonClientArea.cs
- TextEditorSelection.cs
- UrlAuthFailedErrorFormatter.cs
- SapiAttributeParser.cs
- WebBrowserProgressChangedEventHandler.cs
- ContractNamespaceAttribute.cs
- CodeCatchClauseCollection.cs
- Int64Converter.cs
- HierarchicalDataSourceControl.cs
- ActivationWorker.cs
- ModelPropertyDescriptor.cs
- PublisherIdentityPermission.cs
- ACE.cs
- QilFunction.cs
- ProbeDuplex11AsyncResult.cs
- StringHandle.cs
- GetPageCompletedEventArgs.cs
- DataSourceXmlAttributeAttribute.cs
- COM2ExtendedUITypeEditor.cs
- SupportsPreviewControlAttribute.cs
- RelationshipConverter.cs
- WebFormDesignerActionService.cs
- IteratorDescriptor.cs
- BitmapEffect.cs
- WinEventQueueItem.cs
- DetailsViewInsertEventArgs.cs
- BuildProvider.cs
- AssemblyInfo.cs