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
- ConfigurationManagerInternalFactory.cs
- RMEnrollmentPage1.cs
- StringDictionary.cs
- DbConnectionPoolIdentity.cs
- NumericExpr.cs
- BaseServiceProvider.cs
- Rectangle.cs
- FlowNode.cs
- AliasedSlot.cs
- RuntimeCompatibilityAttribute.cs
- XmlSchemaCompilationSettings.cs
- DocumentViewerConstants.cs
- ImagingCache.cs
- VectorAnimationUsingKeyFrames.cs
- JumpItem.cs
- LoginName.cs
- MailAddress.cs
- InkSerializer.cs
- XmlnsDictionary.cs
- ActivityCollectionMarkupSerializer.cs
- NetCodeGroup.cs
- CompositeControlDesigner.cs
- PathHelper.cs
- InvokeProviderWrapper.cs
- CellTreeNodeVisitors.cs
- FamilyTypeface.cs
- DataKey.cs
- NavigationFailedEventArgs.cs
- PathGeometry.cs
- RecognitionResult.cs
- HtmlControl.cs
- MessageSmuggler.cs
- Registry.cs
- UInt16Storage.cs
- CompiledIdentityConstraint.cs
- SupportsEventValidationAttribute.cs
- MasterPageBuildProvider.cs
- Attribute.cs
- WebPartConnectionCollection.cs
- TextTrailingCharacterEllipsis.cs
- ScriptResourceAttribute.cs
- filewebresponse.cs
- MarshalByRefObject.cs
- VirtualDirectoryMapping.cs
- ThreadStaticAttribute.cs
- AnimationException.cs
- XslTransform.cs
- Point3DAnimationBase.cs
- HtmlFormWrapper.cs
- DataConnectionHelper.cs
- KeysConverter.cs
- SecurityElementBase.cs
- RegexWorker.cs
- EventHandlerList.cs
- Msmq4SubqueuePoisonHandler.cs
- SyntaxCheck.cs
- AssemblyResourceLoader.cs
- XamlInterfaces.cs
- HashHelpers.cs
- AppDomainManager.cs
- LineMetrics.cs
- DataViewManagerListItemTypeDescriptor.cs
- SecurityChannelFactory.cs
- ListViewTableCell.cs
- Lease.cs
- CommandValueSerializer.cs
- HyperLink.cs
- HashSetEqualityComparer.cs
- WpfGeneratedKnownProperties.cs
- PropertyEmitterBase.cs
- uribuilder.cs
- GifBitmapEncoder.cs
- WinFormsUtils.cs
- MimeMapping.cs
- DoubleLinkList.cs
- precedingquery.cs
- PeerResolver.cs
- RegistryConfigurationProvider.cs
- XmlUtilWriter.cs
- DbDataReader.cs
- TreeNodeBindingCollection.cs
- FlowLayout.cs
- MorphHelper.cs
- VisualTreeUtils.cs
- NamespaceMapping.cs
- DataGridParentRows.cs
- KeysConverter.cs
- AttributeSetAction.cs
- IRCollection.cs
- CqlBlock.cs
- ToolStripCollectionEditor.cs
- MemberRestriction.cs
- TabPage.cs
- ReachVisualSerializer.cs
- IndexedGlyphRun.cs
- WebPartTracker.cs
- CodeCommentStatementCollection.cs
- ObjectDataSourceSelectingEventArgs.cs
- ProxyElement.cs
- SQLBinaryStorage.cs