Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / KeyManager.cs / 3 / 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
- EdmScalarPropertyAttribute.cs
- GPPOINT.cs
- UnmanagedMemoryStream.cs
- KeyInterop.cs
- PerformanceCountersElement.cs
- BuildResultCache.cs
- LocalizationParserHooks.cs
- ReaderContextStackData.cs
- NavigationHelper.cs
- NativeMethodsCLR.cs
- OrderedEnumerableRowCollection.cs
- SerTrace.cs
- GlobalizationSection.cs
- DbParameterCollectionHelper.cs
- HttpConfigurationContext.cs
- BinaryKeyIdentifierClause.cs
- TextEditorTables.cs
- Types.cs
- InvokeHandlers.cs
- TextTreeUndo.cs
- X509ChainElement.cs
- TextInfo.cs
- EmptyCollection.cs
- SystemIcmpV4Statistics.cs
- SignatureDescription.cs
- DataBindingExpressionBuilder.cs
- SystemBrushes.cs
- UnionCodeGroup.cs
- FieldNameLookup.cs
- DBConnection.cs
- TreeNodeBinding.cs
- OrderedDictionary.cs
- XmlSchemaRedefine.cs
- CharStorage.cs
- NopReturnReader.cs
- TypeDelegator.cs
- SqlStream.cs
- MembershipValidatePasswordEventArgs.cs
- SatelliteContractVersionAttribute.cs
- CollectionConverter.cs
- SoapServerMethod.cs
- XPathMultyIterator.cs
- RectIndependentAnimationStorage.cs
- _ConnectOverlappedAsyncResult.cs
- X509RawDataKeyIdentifierClause.cs
- ObjectIDGenerator.cs
- TextTreeText.cs
- Base64Encoder.cs
- FormViewUpdatedEventArgs.cs
- ColorDialog.cs
- ZipQueryOperator.cs
- StaticContext.cs
- CodeAssignStatement.cs
- PersistencePipeline.cs
- ByteStream.cs
- TypePresenter.xaml.cs
- NameValueFileSectionHandler.cs
- PropertyTabChangedEvent.cs
- DataBoundLiteralControl.cs
- SerializationObjectManager.cs
- Collection.cs
- Int32EqualityComparer.cs
- KeyTime.cs
- ConstNode.cs
- ProxyGenerationError.cs
- DefaultObjectMappingItemCollection.cs
- IdentityValidationException.cs
- SvcFileManager.cs
- DateTimeEditor.cs
- EnumBuilder.cs
- QueryExecutionOption.cs
- ExpressionBuilder.cs
- PropertyRecord.cs
- XPathEmptyIterator.cs
- XamlFigureLengthSerializer.cs
- XmlArrayItemAttributes.cs
- RijndaelManagedTransform.cs
- RegexWorker.cs
- FixedSOMPageConstructor.cs
- ChildChangedEventArgs.cs
- ManualResetEvent.cs
- PreDigestedSignedInfo.cs
- SystemFonts.cs
- DateTimeConverter2.cs
- ForEachAction.cs
- LogicalTreeHelper.cs
- Membership.cs
- CodeIterationStatement.cs
- ReflectionHelper.cs
- GroupByQueryOperator.cs
- NegationPusher.cs
- TextEffect.cs
- SafeNativeMethods.cs
- AmbientLight.cs
- CacheMemory.cs
- HtmlControlDesigner.cs
- LockedActivityGlyph.cs
- StateManagedCollection.cs
- OverrideMode.cs
- ZipIOLocalFileBlock.cs