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
- TemplateKeyConverter.cs
- ItemChangedEventArgs.cs
- DbExpressionRules.cs
- NamespaceCollection.cs
- SemaphoreFullException.cs
- CounterSample.cs
- GifBitmapEncoder.cs
- PopupEventArgs.cs
- EnumerableRowCollectionExtensions.cs
- ApplicationSecurityManager.cs
- CatalogPart.cs
- WorkflowDefinitionDispenser.cs
- CodeSnippetStatement.cs
- TrackBarRenderer.cs
- GeneralTransform3DTo2DTo3D.cs
- XmlSignatureProperties.cs
- InputScopeAttribute.cs
- WizardForm.cs
- StructuralCache.cs
- SignedXml.cs
- SetterBase.cs
- Rotation3DAnimationBase.cs
- InheritablePropertyChangeInfo.cs
- MobileControlBuilder.cs
- MediaSystem.cs
- SrgsRule.cs
- AppSettingsReader.cs
- Item.cs
- WhileDesigner.cs
- CompatibleComparer.cs
- CodeEntryPointMethod.cs
- EntityWrapperFactory.cs
- ToolstripProfessionalRenderer.cs
- XmlSchemaAnnotated.cs
- WebPartZoneCollection.cs
- OptimisticConcurrencyException.cs
- AmbientProperties.cs
- BasicCommandTreeVisitor.cs
- ActivityMetadata.cs
- DataGridViewColumnEventArgs.cs
- DesignTimeResourceProviderFactoryAttribute.cs
- DynamicDataResources.Designer.cs
- XdrBuilder.cs
- DataBindingExpressionBuilder.cs
- FormViewActionList.cs
- ObjectStateManager.cs
- Int16KeyFrameCollection.cs
- TargetConverter.cs
- QilFactory.cs
- WebPartConnectVerb.cs
- GlyphsSerializer.cs
- DoubleConverter.cs
- Buffer.cs
- DataSourceGroupCollection.cs
- DataRowExtensions.cs
- Rfc2898DeriveBytes.cs
- CellRelation.cs
- streamingZipPartStream.cs
- RefreshEventArgs.cs
- RewritingPass.cs
- DebuggerAttributes.cs
- smtppermission.cs
- BamlBinaryReader.cs
- Configuration.cs
- HttpRequestWrapper.cs
- DataRelationCollection.cs
- AddInStore.cs
- ExecutionContext.cs
- XhtmlCssHandler.cs
- AccessibleObject.cs
- BamlLocalizer.cs
- MostlySingletonList.cs
- TypeDescriptor.cs
- ModuleBuilder.cs
- AesManaged.cs
- TreePrinter.cs
- LinkArea.cs
- EnumMember.cs
- MD5.cs
- IndexedString.cs
- IPipelineRuntime.cs
- Pointer.cs
- ClientTargetSection.cs
- DashStyles.cs
- MsmqIntegrationMessageProperty.cs
- ItemsControlAutomationPeer.cs
- SimpleBitVector32.cs
- MessageHeaderT.cs
- RevocationPoint.cs
- HttpAsyncResult.cs
- MarkupCompiler.cs
- XmlName.cs
- InputScopeManager.cs
- _SslState.cs
- DataContractSerializer.cs
- DivideByZeroException.cs
- CodeGotoStatement.cs
- SQLDecimal.cs
- Int32Collection.cs
- Expressions.cs