Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / 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
- TextRenderer.cs
- PagesChangedEventArgs.cs
- Floater.cs
- Request.cs
- IntegerValidatorAttribute.cs
- RSAPKCS1SignatureDeformatter.cs
- PropertyDescriptors.cs
- DetailsViewInsertEventArgs.cs
- OutputCacheSection.cs
- ScriptingProfileServiceSection.cs
- RelationshipDetailsRow.cs
- PropertyValueUIItem.cs
- GridViewRow.cs
- ZoomingMessageFilter.cs
- Msec.cs
- ParserStreamGeometryContext.cs
- CroppedBitmap.cs
- DesignerDataSourceView.cs
- MSAAEventDispatcher.cs
- TextRenderer.cs
- Timer.cs
- DataGridViewElement.cs
- WpfWebRequestHelper.cs
- AssemblyResourceLoader.cs
- DocumentPageViewAutomationPeer.cs
- DataGridToolTip.cs
- MatrixAnimationUsingPath.cs
- DataGridViewCellEventArgs.cs
- CallContext.cs
- TextParagraphView.cs
- SoapCodeExporter.cs
- Ref.cs
- EdmMember.cs
- NumberSubstitution.cs
- XmlBaseWriter.cs
- DecimalAnimationUsingKeyFrames.cs
- CompilerLocalReference.cs
- CompilerTypeWithParams.cs
- ReadOnlyDataSourceView.cs
- CustomErrorsSection.cs
- ReflectionTypeLoadException.cs
- FloatSumAggregationOperator.cs
- BuildResultCache.cs
- VScrollProperties.cs
- ValidatedControlConverter.cs
- AnnotationResource.cs
- QueryResults.cs
- TextFormatterImp.cs
- StreamWriter.cs
- MultiView.cs
- ZipIOExtraFieldZip64Element.cs
- AddingNewEventArgs.cs
- Classification.cs
- InheritedPropertyDescriptor.cs
- BufferedMessageWriter.cs
- OperatorExpressions.cs
- SpeechSynthesizer.cs
- SerializerWriterEventHandlers.cs
- FormViewInsertedEventArgs.cs
- Vector.cs
- DebugHandleTracker.cs
- PanelDesigner.cs
- ImpersonateTokenRef.cs
- TextWriterTraceListener.cs
- CachedBitmap.cs
- ReturnType.cs
- XdrBuilder.cs
- StringValueSerializer.cs
- InfoCardService.cs
- ArrangedElementCollection.cs
- DistributedTransactionPermission.cs
- TextEditorMouse.cs
- AxImporter.cs
- SafePointer.cs
- CellParaClient.cs
- DataGridViewCheckBoxCell.cs
- AuthenticationConfig.cs
- ExponentialEase.cs
- GeometryGroup.cs
- TextFormatterHost.cs
- FileLogRecordEnumerator.cs
- TableLayoutStyle.cs
- CleanUpVirtualizedItemEventArgs.cs
- EncoderReplacementFallback.cs
- ClientData.cs
- QuaternionAnimationUsingKeyFrames.cs
- Buffer.cs
- NotCondition.cs
- GridViewUpdateEventArgs.cs
- InputScopeNameConverter.cs
- SymmetricSecurityProtocol.cs
- PtsPage.cs
- BuildTopDownAttribute.cs
- XamlSerializationHelper.cs
- MemberJoinTreeNode.cs
- Lasso.cs
- FieldAccessException.cs
- XPathNodeInfoAtom.cs
- FixedTextView.cs
- HtmlInputPassword.cs