Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / KeyManager.cs / 1 / KeyManager.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Common.Utils; using System.Collections.Generic; using System.Diagnostics; using System.Collections.ObjectModel; using System.Linq; using System.Data.Entity; using NodeColor = System.Byte; namespace System.Data.Mapping.Update.Internal { ////// Manages interactions between keys in the update pipeline (e.g. via referential constraints) /// internal class KeyManager { #region Fields private readonly Dictionary_keyIdentifiers; private readonly Dictionary _identifierOwners; private readonly KeyToListMap _dependentStateEntries; private readonly KeyToListMap _identifierRefConstraints; private readonly UpdateTranslator _translator; private Partitioner _commonValuePartitioner; private Int64 _identifier; private const NodeColor Black = 1; private const NodeColor Gray = 2; #endregion #region Constructors internal KeyManager(UpdateTranslator translator) { _translator = EntityUtil.CheckArgumentNull(translator, "translator"); _keyIdentifiers = new Dictionary (EqualityComparer .Default); _identifierRefConstraints = new KeyToListMap (EqualityComparer .Default); _dependentStateEntries = new KeyToListMap (EqualityComparer .Default); _identifierOwners = new Dictionary (); _commonValuePartitioner = new Partitioner(); } #endregion #region Methods /// /// Given an identifier, returns the canonical identifier for the clique including all identifiers /// with the same value (via referential integrity constraints). /// internal long GetCanonicalIdentifier(long identifier) { if (null == _commonValuePartitioner) { return identifier; } return _commonValuePartitioner.GetPartitionId(identifier); } ////// Indicate that the principal identifier controls the value for the dependent identifier. /// internal void AddReferentialConstraint(IEntityStateEntry dependentStateEntry, long dependentIdentifier, long principalIdentifier) { // A value is trivially constrained to be itself if (dependentIdentifier != principalIdentifier) { if (null == _commonValuePartitioner) { _commonValuePartitioner = new Partitioner(); } // track these as 'common values'; used to determine canonical identifier for dependency // ordering and validation of constraints _commonValuePartitioner.AssociateNodes(dependentIdentifier, principalIdentifier); // remember the constraint _identifierRefConstraints.Add(dependentIdentifier, principalIdentifier); } _dependentStateEntries.Add(dependentIdentifier, dependentStateEntry); } ////// Given an 'identifier' result, register it as the owner (for purposes of error reporting, /// since common value results can sometimes get projected out after a join) /// internal void RegisterIdentifierOwner(PropagatorResult owner) { Debug.Assert(PropagatorResult.NullIdentifier != owner.Identifier, "invalid operation for a " + "result without an identifier"); _identifierOwners[owner.Identifier] = owner; } ////// Checks if the given identifier has a registered 'owner' /// internal bool TryGetIdentifierOwner(long identifier, out PropagatorResult owner) { return _identifierOwners.TryGetValue(identifier, out owner); } ////// Gets identifier for an entity key member at the given offset (ordinal of the property /// in the key properties for the relevant entity set) /// internal long GetKeyIdentifierForMemberOffset(EntityKey entityKey, int memberOffset, int keyMemberCount) { long result; // get offset for first element of key if (!_keyIdentifiers.TryGetValue(entityKey, out result)) { result = _identifier; _identifier += keyMemberCount; _keyIdentifiers.Add(entityKey, result); } // add memberOffset relative to first element of key result += memberOffset; return result; } ////// Gets all relationship entries constrained by the given identifier. If there is a referential constraint /// where the identifier is the principal, returns results corresponding to the constrained /// dependent relationships. /// internal IEnumerableGetDependentStateEntries(long identifier) { return _dependentStateEntries.EnumerateValues(identifier); } /// /// Given a value, returns the value for its principal owner. /// internal object GetPrincipalValue(PropagatorResult result) { long currentIdentifier = result.Identifier; if (PropagatorResult.NullIdentifier == currentIdentifier) { // for non-identifiers, there is nothing to resolve return result.GetSimpleValue(); } // find principals for this value bool first = true; object value = null; foreach (long principal in GetPrincipals(currentIdentifier)) { PropagatorResult ownerResult; if (_identifierOwners.TryGetValue(principal, out ownerResult)) { if (first) { // result is taken from the first principal value = ownerResult.GetSimpleValue(); first = false; } else { // subsequent results are validated for consistency with the first if (!CdpEqualityComparer.DefaultEqualityComparer.Equals(value, ownerResult.GetSimpleValue())) { throw EntityUtil.Constraint(System.Data.Entity.Strings.Update_ReferentialConstraintIntegrityViolation); } } } } if (first) { // if there are no principals, return the current value directly value = result.GetSimpleValue(); } return value; } ////// Gives all principals affecting the given identifier. /// internal IEnumerableGetPrincipals(long identifier) { Stack stack = new Stack (); stack.Push(identifier); // using a non-recursive implementation to avoid overhead of recursive yields while (stack.Count > 0) { long currentIdentifier = stack.Pop(); ReadOnlyCollection principals; if (_identifierRefConstraints.TryGetListForKey(currentIdentifier, out principals)) { foreach (long principal in principals) { stack.Push(principal); } } else { yield return currentIdentifier; } } } /// /// Checks whether the given identifier has any contributing principals. /// internal bool HasPrincipals(long identifier) { return _identifierRefConstraints.ContainsKey(identifier); } ////// Checks whether there is a cycle in the identifier graph. /// internal void ValidateReferentialIntegrityGraphAcyclic() { // _identifierRefConstraints describes the referential integrity // 'identifier' graph. How is a conflict // even possible? The state manager does not enforce integrity // constraints but rather forces them to be satisfied. In other words, // the dependent entity takes the value of its parent. If a parent // is also a child however, there is no way of determining which one // controls the value. // Standard DFS search // Color nodes as we traverse the graph: no entry means we have not // explored a node yet, Gray means we are currently visiting a node, and Black means // we have finished visiting a node. Dictionarycolor = new Dictionary (); foreach (long node in _identifierRefConstraints.Keys) { if (!color.ContainsKey(node)) { ValidateReferentialIntegrityGraphAcyclic(node, color, null); } } } private void ValidateReferentialIntegrityGraphAcyclic(long node, Dictionary color, IdentifierPath parent) { color[node] = Gray; // color the node to indicate we're visiting it IdentifierPath path = new IdentifierPath(node, parent); foreach (long successor in _identifierRefConstraints.EnumerateValues(node)) { NodeColor successorColor; if (color.TryGetValue(successor, out successorColor)) { // if we're currently visiting the successor, there is a cycle if (successorColor == Gray) { Debug.Assert(path.GetPath().Contains(successor), "a node should be marked Gray " + "only while we're visiting it (which implies it must be in the path"); // recover all affected entities from the path (keep on walking // until we hit the 'successor' again which bounds the cycle) List stateEntriesInCycle = new List (); foreach (long identifierInCycle in path.GetPath()) { PropagatorResult owner; if (_identifierOwners.TryGetValue(identifierInCycle, out owner)) { stateEntriesInCycle.Add(owner.StateEntry); } if (identifierInCycle == successor) { // cycle complete break; } } throw EntityUtil.Update(Strings.Update_CircularRelationships, null, stateEntriesInCycle); } } else { // haven't seen this node yet; visit it ValidateReferentialIntegrityGraphAcyclic(successor, color, path); } } color[node] = Black; // color the node to indicate we're done visiting it } #endregion /// /// Supports grouping 'nodes' represented as long identifiers into partitions (where the /// identifier for the partition is the identifier for an arbitrary node in that partition). /// Note: internally, we only track partitions where there is more than one node. /// private class Partitioner { private readonly Dictionary_nodeIdToPartitionMap; internal Partitioner() { _nodeIdToPartitionMap = new Dictionary (); } /// /// Gets identifier for the partition of the given node identifier. /// internal long GetPartitionId(long id) { Partition partition; if (_nodeIdToPartitionMap.TryGetValue(id, out partition)) { return partition.PartitionId; } // if there is no explicit (count > 1) partition, the node is its own // partition return id; } ////// Ensures firstId and secondId belong to the same partition /// internal void AssociateNodes(long firstId, long secondId) { if (firstId == secondId) { // A node is (trivially) associated with itself return; } Partition firstPartition; if (_nodeIdToPartitionMap.TryGetValue(firstId, out firstPartition)) { Partition secondPartition; if (_nodeIdToPartitionMap.TryGetValue(secondId, out secondPartition)) { // merge partitions firstPartition.Merge(this, secondPartition); } else { // add y to existing x partition firstPartition.AddNode(this, secondId); } } else { Partition secondPartition; if (_nodeIdToPartitionMap.TryGetValue(secondId, out secondPartition)) { // add x to existing y partition secondPartition.AddNode(this, firstId); } else { // Neither node is known Partition.CreatePartition(this, firstId, secondId); } } } private class Partition { internal readonly long PartitionId; private List_nodeIds; private Partition(long partitionId) { _nodeIds = new List (2); PartitionId = partitionId; } internal static void CreatePartition(Partitioner partitioner, long firstId, long secondId) { Partition partition = new Partition(firstId); partition.AddNode(partitioner, firstId); partition.AddNode(partitioner, secondId); } internal void AddNode(Partitioner partitioner, long nodeId) { Debug.Assert(!_nodeIds.Contains(nodeId), "don't add existing node to partition"); _nodeIds.Add(nodeId); partitioner._nodeIdToPartitionMap[nodeId] = this; } internal void Merge(Partitioner partitioner, Partition other) { if (other.PartitionId == this.PartitionId) { return; } foreach (long element in other._nodeIds) { // reparent the node AddNode(partitioner, element); } } } } /// /// Simple linked list class supporting tracing a sequence of identifiers. Used /// to report cycles in referential integrity constraints. /// private sealed class IdentifierPath { private readonly long _identifier; private readonly IdentifierPath _parent; internal IdentifierPath(long identifier, IdentifierPath parent) { _identifier = identifier; _parent = parent; } internal IEnumerableGetPath() { IdentifierPath current = this; while (null != current) { yield return current._identifier; current = current._parent; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Data.Common.Utils; using System.Collections.Generic; using System.Diagnostics; using System.Collections.ObjectModel; using System.Linq; using System.Data.Entity; using NodeColor = System.Byte; namespace System.Data.Mapping.Update.Internal { ////// Manages interactions between keys in the update pipeline (e.g. via referential constraints) /// internal class KeyManager { #region Fields private readonly Dictionary_keyIdentifiers; private readonly Dictionary _identifierOwners; private readonly KeyToListMap _dependentStateEntries; private readonly KeyToListMap _identifierRefConstraints; private readonly UpdateTranslator _translator; private Partitioner _commonValuePartitioner; private Int64 _identifier; private const NodeColor Black = 1; private const NodeColor Gray = 2; #endregion #region Constructors internal KeyManager(UpdateTranslator translator) { _translator = EntityUtil.CheckArgumentNull(translator, "translator"); _keyIdentifiers = new Dictionary (EqualityComparer .Default); _identifierRefConstraints = new KeyToListMap (EqualityComparer .Default); _dependentStateEntries = new KeyToListMap (EqualityComparer .Default); _identifierOwners = new Dictionary (); _commonValuePartitioner = new Partitioner(); } #endregion #region Methods /// /// Given an identifier, returns the canonical identifier for the clique including all identifiers /// with the same value (via referential integrity constraints). /// internal long GetCanonicalIdentifier(long identifier) { if (null == _commonValuePartitioner) { return identifier; } return _commonValuePartitioner.GetPartitionId(identifier); } ////// Indicate that the principal identifier controls the value for the dependent identifier. /// internal void AddReferentialConstraint(IEntityStateEntry dependentStateEntry, long dependentIdentifier, long principalIdentifier) { // A value is trivially constrained to be itself if (dependentIdentifier != principalIdentifier) { if (null == _commonValuePartitioner) { _commonValuePartitioner = new Partitioner(); } // track these as 'common values'; used to determine canonical identifier for dependency // ordering and validation of constraints _commonValuePartitioner.AssociateNodes(dependentIdentifier, principalIdentifier); // remember the constraint _identifierRefConstraints.Add(dependentIdentifier, principalIdentifier); } _dependentStateEntries.Add(dependentIdentifier, dependentStateEntry); } ////// Given an 'identifier' result, register it as the owner (for purposes of error reporting, /// since common value results can sometimes get projected out after a join) /// internal void RegisterIdentifierOwner(PropagatorResult owner) { Debug.Assert(PropagatorResult.NullIdentifier != owner.Identifier, "invalid operation for a " + "result without an identifier"); _identifierOwners[owner.Identifier] = owner; } ////// Checks if the given identifier has a registered 'owner' /// internal bool TryGetIdentifierOwner(long identifier, out PropagatorResult owner) { return _identifierOwners.TryGetValue(identifier, out owner); } ////// Gets identifier for an entity key member at the given offset (ordinal of the property /// in the key properties for the relevant entity set) /// internal long GetKeyIdentifierForMemberOffset(EntityKey entityKey, int memberOffset, int keyMemberCount) { long result; // get offset for first element of key if (!_keyIdentifiers.TryGetValue(entityKey, out result)) { result = _identifier; _identifier += keyMemberCount; _keyIdentifiers.Add(entityKey, result); } // add memberOffset relative to first element of key result += memberOffset; return result; } ////// Gets all relationship entries constrained by the given identifier. If there is a referential constraint /// where the identifier is the principal, returns results corresponding to the constrained /// dependent relationships. /// internal IEnumerableGetDependentStateEntries(long identifier) { return _dependentStateEntries.EnumerateValues(identifier); } /// /// Given a value, returns the value for its principal owner. /// internal object GetPrincipalValue(PropagatorResult result) { long currentIdentifier = result.Identifier; if (PropagatorResult.NullIdentifier == currentIdentifier) { // for non-identifiers, there is nothing to resolve return result.GetSimpleValue(); } // find principals for this value bool first = true; object value = null; foreach (long principal in GetPrincipals(currentIdentifier)) { PropagatorResult ownerResult; if (_identifierOwners.TryGetValue(principal, out ownerResult)) { if (first) { // result is taken from the first principal value = ownerResult.GetSimpleValue(); first = false; } else { // subsequent results are validated for consistency with the first if (!CdpEqualityComparer.DefaultEqualityComparer.Equals(value, ownerResult.GetSimpleValue())) { throw EntityUtil.Constraint(System.Data.Entity.Strings.Update_ReferentialConstraintIntegrityViolation); } } } } if (first) { // if there are no principals, return the current value directly value = result.GetSimpleValue(); } return value; } ////// Gives all principals affecting the given identifier. /// internal IEnumerableGetPrincipals(long identifier) { Stack stack = new Stack (); stack.Push(identifier); // using a non-recursive implementation to avoid overhead of recursive yields while (stack.Count > 0) { long currentIdentifier = stack.Pop(); ReadOnlyCollection principals; if (_identifierRefConstraints.TryGetListForKey(currentIdentifier, out principals)) { foreach (long principal in principals) { stack.Push(principal); } } else { yield return currentIdentifier; } } } /// /// Checks whether the given identifier has any contributing principals. /// internal bool HasPrincipals(long identifier) { return _identifierRefConstraints.ContainsKey(identifier); } ////// Checks whether there is a cycle in the identifier graph. /// internal void ValidateReferentialIntegrityGraphAcyclic() { // _identifierRefConstraints describes the referential integrity // 'identifier' graph. How is a conflict // even possible? The state manager does not enforce integrity // constraints but rather forces them to be satisfied. In other words, // the dependent entity takes the value of its parent. If a parent // is also a child however, there is no way of determining which one // controls the value. // Standard DFS search // Color nodes as we traverse the graph: no entry means we have not // explored a node yet, Gray means we are currently visiting a node, and Black means // we have finished visiting a node. Dictionarycolor = new Dictionary (); foreach (long node in _identifierRefConstraints.Keys) { if (!color.ContainsKey(node)) { ValidateReferentialIntegrityGraphAcyclic(node, color, null); } } } private void ValidateReferentialIntegrityGraphAcyclic(long node, Dictionary color, IdentifierPath parent) { color[node] = Gray; // color the node to indicate we're visiting it IdentifierPath path = new IdentifierPath(node, parent); foreach (long successor in _identifierRefConstraints.EnumerateValues(node)) { NodeColor successorColor; if (color.TryGetValue(successor, out successorColor)) { // if we're currently visiting the successor, there is a cycle if (successorColor == Gray) { Debug.Assert(path.GetPath().Contains(successor), "a node should be marked Gray " + "only while we're visiting it (which implies it must be in the path"); // recover all affected entities from the path (keep on walking // until we hit the 'successor' again which bounds the cycle) List stateEntriesInCycle = new List (); foreach (long identifierInCycle in path.GetPath()) { PropagatorResult owner; if (_identifierOwners.TryGetValue(identifierInCycle, out owner)) { stateEntriesInCycle.Add(owner.StateEntry); } if (identifierInCycle == successor) { // cycle complete break; } } throw EntityUtil.Update(Strings.Update_CircularRelationships, null, stateEntriesInCycle); } } else { // haven't seen this node yet; visit it ValidateReferentialIntegrityGraphAcyclic(successor, color, path); } } color[node] = Black; // color the node to indicate we're done visiting it } #endregion /// /// Supports grouping 'nodes' represented as long identifiers into partitions (where the /// identifier for the partition is the identifier for an arbitrary node in that partition). /// Note: internally, we only track partitions where there is more than one node. /// private class Partitioner { private readonly Dictionary_nodeIdToPartitionMap; internal Partitioner() { _nodeIdToPartitionMap = new Dictionary (); } /// /// Gets identifier for the partition of the given node identifier. /// internal long GetPartitionId(long id) { Partition partition; if (_nodeIdToPartitionMap.TryGetValue(id, out partition)) { return partition.PartitionId; } // if there is no explicit (count > 1) partition, the node is its own // partition return id; } ////// Ensures firstId and secondId belong to the same partition /// internal void AssociateNodes(long firstId, long secondId) { if (firstId == secondId) { // A node is (trivially) associated with itself return; } Partition firstPartition; if (_nodeIdToPartitionMap.TryGetValue(firstId, out firstPartition)) { Partition secondPartition; if (_nodeIdToPartitionMap.TryGetValue(secondId, out secondPartition)) { // merge partitions firstPartition.Merge(this, secondPartition); } else { // add y to existing x partition firstPartition.AddNode(this, secondId); } } else { Partition secondPartition; if (_nodeIdToPartitionMap.TryGetValue(secondId, out secondPartition)) { // add x to existing y partition secondPartition.AddNode(this, firstId); } else { // Neither node is known Partition.CreatePartition(this, firstId, secondId); } } } private class Partition { internal readonly long PartitionId; private List_nodeIds; private Partition(long partitionId) { _nodeIds = new List (2); PartitionId = partitionId; } internal static void CreatePartition(Partitioner partitioner, long firstId, long secondId) { Partition partition = new Partition(firstId); partition.AddNode(partitioner, firstId); partition.AddNode(partitioner, secondId); } internal void AddNode(Partitioner partitioner, long nodeId) { Debug.Assert(!_nodeIds.Contains(nodeId), "don't add existing node to partition"); _nodeIds.Add(nodeId); partitioner._nodeIdToPartitionMap[nodeId] = this; } internal void Merge(Partitioner partitioner, Partition other) { if (other.PartitionId == this.PartitionId) { return; } foreach (long element in other._nodeIds) { // reparent the node AddNode(partitioner, element); } } } } /// /// Simple linked list class supporting tracing a sequence of identifiers. Used /// to report cycles in referential integrity constraints. /// private sealed class IdentifierPath { private readonly long _identifier; private readonly IdentifierPath _parent; internal IdentifierPath(long identifier, IdentifierPath parent) { _identifier = identifier; _parent = parent; } internal IEnumerableGetPath() { IdentifierPath current = this; while (null != current) { yield return current._identifier; current = current._parent; } } } } } // 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
- DependencyProperty.cs
- DrawingContextDrawingContextWalker.cs
- AttributeCollection.cs
- OLEDB_Util.cs
- XmlSecureResolver.cs
- ObjectDataSourceMethodEventArgs.cs
- DataGridItem.cs
- MessageDroppedTraceRecord.cs
- StorageAssociationTypeMapping.cs
- StorageModelBuildProvider.cs
- SchemaTableColumn.cs
- WhitespaceSignificantCollectionAttribute.cs
- SiteMapSection.cs
- XmlUtil.cs
- X509DefaultServiceCertificateElement.cs
- ManagementDateTime.cs
- Vector3dCollection.cs
- SystemThemeKey.cs
- ThemeableAttribute.cs
- TraceData.cs
- ToolStripSeparatorRenderEventArgs.cs
- Focus.cs
- XMLDiffLoader.cs
- CollectionCodeDomSerializer.cs
- QueryStringParameter.cs
- FixedFindEngine.cs
- UnicastIPAddressInformationCollection.cs
- SQLDateTimeStorage.cs
- ProcessModule.cs
- ToolTipAutomationPeer.cs
- Parsers.cs
- SingleConverter.cs
- Emitter.cs
- IDReferencePropertyAttribute.cs
- RegexTree.cs
- ContentElementAutomationPeer.cs
- TransactionChannelFaultConverter.cs
- StylusCaptureWithinProperty.cs
- TextServicesProperty.cs
- BuildProviderUtils.cs
- TransformedBitmap.cs
- ObsoleteAttribute.cs
- XsltSettings.cs
- CaseInsensitiveOrdinalStringComparer.cs
- HtmlObjectListAdapter.cs
- ControlPersister.cs
- Range.cs
- MediaPlayer.cs
- ConstraintEnumerator.cs
- StylusOverProperty.cs
- SignatureDescription.cs
- SmtpFailedRecipientsException.cs
- TreeNodeCollection.cs
- ConnectionPoolManager.cs
- MsmqProcessProtocolHandler.cs
- validationstate.cs
- SchemaInfo.cs
- Logging.cs
- UniqueConstraint.cs
- SByte.cs
- SetterBaseCollection.cs
- UnsafeNativeMethods.cs
- CheckBox.cs
- PrintPreviewDialog.cs
- VisualStyleTypesAndProperties.cs
- SerializationSectionGroup.cs
- EditBehavior.cs
- DbConnectionHelper.cs
- XmlSchemaSimpleContentExtension.cs
- WeakReference.cs
- _WinHttpWebProxyDataBuilder.cs
- StringUtil.cs
- WizardStepBase.cs
- ActiveXHelper.cs
- DataGridDetailsPresenterAutomationPeer.cs
- ObjectContextServiceProvider.cs
- XmlBindingWorker.cs
- WebDescriptionAttribute.cs
- TextTreeRootTextBlock.cs
- OleDbRowUpdatedEvent.cs
- Int16Converter.cs
- CodeIndexerExpression.cs
- XmlSchemaAttributeGroup.cs
- DesignSurfaceCollection.cs
- ImageKeyConverter.cs
- SafeTimerHandle.cs
- EntityDataSourceDesignerHelper.cs
- SpellerInterop.cs
- OleDbDataReader.cs
- CipherData.cs
- XmlCharCheckingWriter.cs
- FileDialog.cs
- CryptoProvider.cs
- SecurityHelper.cs
- XmlSchemaValidator.cs
- EncoderReplacementFallback.cs
- LoginAutoFormat.cs
- SqlTypesSchemaImporter.cs
- TrackingProfile.cs