Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Map / Update / Internal / KeyManager.cs / 1305376 / 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, int> _foreignKeyIdentifiers = new Dictionary , int>(); private readonly Dictionary _valueKeyToTempKey = new Dictionary (); private readonly Dictionary _keyIdentifiers = new Dictionary (); private readonly List _identifiers = new List () { new IdentifierInfo() }; private readonly UpdateTranslator _translator; private const NodeColor White = 0; private const NodeColor Black = 1; private const NodeColor Gray = 2; #endregion #region Constructors internal KeyManager(UpdateTranslator translator) { _translator = EntityUtil.CheckArgumentNull(translator, "translator"); } #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 int GetCliqueIdentifier(int identifier) { Partition partition = _identifiers[identifier].Partition; if (null != partition) { return partition.PartitionId; } // if there is no explicit (count > 1) partition, the node is its own // partition return identifier; } ////// Indicate that the principal identifier controls the value for the dependent identifier. /// internal void AddReferentialConstraint(IEntityStateEntry dependentStateEntry, int dependentIdentifier, int principalIdentifier) { IdentifierInfo dependentInfo = _identifiers[dependentIdentifier]; // A value is trivially constrained to be itself if (dependentIdentifier != principalIdentifier) { // track these as 'equivalent values'; used to determine canonical identifier for dependency // ordering and validation of constraints AssociateNodes(dependentIdentifier, principalIdentifier); // remember the constraint LinkedList.Add(ref dependentInfo.References, principalIdentifier); IdentifierInfo principalInfo = _identifiers[principalIdentifier]; LinkedList .Add(ref principalInfo.ReferencedBy, dependentIdentifier); } LinkedList .Add(ref dependentInfo.DependentStateEntries, dependentStateEntry); } /// /// Given an 'identifier' result, register it as the owner (for purposes of error reporting, /// since foreign key 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"); _identifiers[owner.Identifier].Owner = owner; } ////// Checks if the given identifier has a registered 'owner' /// internal bool TryGetIdentifierOwner(int identifier, out PropagatorResult owner) { owner = _identifiers[identifier].Owner; return null != 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 int GetKeyIdentifierForMemberOffset(EntityKey entityKey, int memberOffset, int keyMemberCount) { int result; // get offset for first element of key if (!_keyIdentifiers.TryGetValue(entityKey, out result)) { result = _identifiers.Count; for (int i = 0; i < keyMemberCount; i++) { _identifiers.Add(new IdentifierInfo()); } _keyIdentifiers.Add(entityKey, result); } // add memberOffset relative to first element of key result += memberOffset; return result; } ////// Creates identifier for a (non-key) entity member (or return existing identifier). /// internal int GetKeyIdentifierForMember(EntityKey entityKey, string member, bool currentValues) { int result; var position = Tuple.Create(entityKey, member, currentValues); if (!_foreignKeyIdentifiers.TryGetValue(position, out result)) { result = _identifiers.Count; _identifiers.Add(new IdentifierInfo()); _foreignKeyIdentifiers.Add(position, result); } 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(int identifier) { return LinkedList .Enumerate(_identifiers[identifier].DependentStateEntries); } /// /// Given a value, returns the value for its principal owner. /// internal object GetPrincipalValue(PropagatorResult result) { int 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 (int principal in GetPrincipals(currentIdentifier)) { PropagatorResult ownerResult = _identifiers[principal].Owner; if (null != 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 (!ByValueEqualityComparer.Default.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(int identifier) { return WalkGraph(identifier, (info) => info.References, true); } /// /// Gets all dependents affected by the given identifier. /// internal IEnumerableGetDependents(int identifier) { return WalkGraph(identifier, (info) => info.ReferencedBy, false); } private IEnumerable WalkGraph(int identifier, Func > successorFunction, bool leavesOnly) { var stack = new Stack (); stack.Push(identifier); // using a non-recursive implementation to avoid overhead of recursive yields while (stack.Count > 0) { int currentIdentifier = stack.Pop(); LinkedList successors = successorFunction(_identifiers[currentIdentifier]); if (null != successors) { foreach (int successor in LinkedList .Enumerate(successors)) { stack.Push(successor); } if (!leavesOnly) { yield return currentIdentifier; } } else { yield return currentIdentifier; } } } /// /// Checks whether the given identifier has any contributing principals. /// internal bool HasPrincipals(int identifier) { return null != _identifiers[identifier].References; } ////// 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: White 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. var color = new NodeColor[_identifiers.Count]; for (int i = 0, n = _identifiers.Count; i < n; i++) { if (color[i] == White) { ValidateReferentialIntegrityGraphAcyclic(i, color, null); } } } ////// Registers an added entity so that it can be matched by a foreign key lookup. /// internal void RegisterKeyValueForAddedEntity(IEntityStateEntry addedEntry) { Debug.Assert(null != addedEntry); Debug.Assert(!addedEntry.IsRelationship); Debug.Assert(!addedEntry.IsKeyEntry); Debug.Assert(addedEntry.EntityKey.IsTemporary); // map temp key to 'value' key (if all values of the key are non null) EntityKey tempKey = addedEntry.EntityKey; EntityKey valueKey; var keyMembers = addedEntry.EntitySet.ElementType.KeyMembers; var currentValues = addedEntry.CurrentValues; object[] keyValues = new object[keyMembers.Count]; bool hasNullValue = false; for (int i = 0, n = keyMembers.Count; i < n; i++) { int ordinal = currentValues.GetOrdinal(keyMembers[i].Name); if (currentValues.IsDBNull(ordinal)) { hasNullValue = true; break; } else { keyValues[i] = currentValues.GetValue(ordinal); } } if (hasNullValue) { return; } else { valueKey = keyValues.Length == 1 ? new EntityKey(addedEntry.EntitySet, keyValues[0]) : new EntityKey(addedEntry.EntitySet, keyValues); } if (_valueKeyToTempKey.ContainsKey(valueKey)) { // null indicates that there are collisions on key values _valueKeyToTempKey[valueKey] = null; } else { _valueKeyToTempKey.Add(valueKey, tempKey); } } ////// There are three states: /// /// - No temp keys with the given value exists (return false, out null) /// - A single temp key exists with the given value (return true, out non null) /// - Multiple temp keys exist with the given value (return true, out null) /// internal bool TryGetTempKey(EntityKey valueKey, out EntityKey tempKey) { return _valueKeyToTempKey.TryGetValue(valueKey, out tempKey); } private void ValidateReferentialIntegrityGraphAcyclic(int node, NodeColor[] color, LinkedListparent) { color[node] = Gray; // color the node to indicate we're visiting it LinkedList .Add(ref parent, node); foreach (int successor in LinkedList .Enumerate(_identifiers[node].References)) { switch (color[successor]) { case White: // haven't seen this node yet; visit it ValidateReferentialIntegrityGraphAcyclic(successor, color, parent); break; case Gray: { // 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 (int identifierInCycle in LinkedList .Enumerate(parent)) { PropagatorResult owner = _identifiers[identifierInCycle].Owner; if (null != owner) { stateEntriesInCycle.Add(owner.StateEntry); } if (identifierInCycle == successor) { // cycle complete break; } } throw EntityUtil.Update(Strings.Update_CircularRelationships, null, stateEntriesInCycle); } default: // done break; } } color[node] = Black; // color the node to indicate we're done visiting it } #endregion /// /// Ensures firstId and secondId belong to the same partition /// internal void AssociateNodes(int firstId, int secondId) { if (firstId == secondId) { // A node is (trivially) associated with itself return; } Partition firstPartition = _identifiers[firstId].Partition; if (null != firstPartition) { Partition secondPartition = _identifiers[secondId].Partition; if (null != secondPartition) { // merge partitions firstPartition.Merge(this, secondPartition); } else { // add y to existing x partition firstPartition.AddNode(this, secondId); } } else { Partition secondPartition = _identifiers[secondId].Partition; if (null != secondPartition) { // add x to existing y partition secondPartition.AddNode(this, firstId); } else { // Neither node is known Partition.CreatePartition(this, firstId, secondId); } } } private sealed class Partition { internal readonly int PartitionId; private readonly List_nodeIds; private Partition(int partitionId) { _nodeIds = new List (2); PartitionId = partitionId; } internal static void CreatePartition(KeyManager manager, int firstId, int secondId) { Partition partition = new Partition(firstId); partition.AddNode(manager, firstId); partition.AddNode(manager, secondId); } internal void AddNode(KeyManager manager, int nodeId) { Debug.Assert(!_nodeIds.Contains(nodeId), "don't add existing node to partition"); _nodeIds.Add(nodeId); manager._identifiers[nodeId].Partition = this; } internal void Merge(KeyManager manager, Partition other) { if (other.PartitionId == this.PartitionId) { return; } foreach (int element in other._nodeIds) { // reparent the node AddNode(manager, element); } } } /// /// Simple linked list class. /// private sealed class LinkedList{ private readonly T _value; private readonly LinkedList _previous; private LinkedList(T value, LinkedList previous) { _value = value; _previous = previous; } internal static IEnumerable Enumerate(LinkedList current) { while (null != current) { yield return current._value; current = current._previous; } } internal static void Add(ref LinkedList list, T value) { list = new LinkedList (value, list); } } /// /// Collects information relevant to a particular identifier. /// private sealed class IdentifierInfo { internal Partition Partition; internal PropagatorResult Owner; internal LinkedListDependentStateEntries; internal LinkedList References; internal LinkedList ReferencedBy; } } } // 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
- PointAnimation.cs
- CodeIdentifier.cs
- KeyPressEvent.cs
- SafeFileHandle.cs
- TraceProvider.cs
- IgnoreFlushAndCloseStream.cs
- DecryptedHeader.cs
- TimeSpanConverter.cs
- EventLogPermission.cs
- PolyLineSegment.cs
- ControlIdConverter.cs
- DirectoryNotFoundException.cs
- RoleGroup.cs
- CqlLexer.cs
- InputBinding.cs
- PackagePartCollection.cs
- UInt16Converter.cs
- ParallelDesigner.cs
- BackgroundWorker.cs
- UpdateEventArgs.cs
- DataSourceControlBuilder.cs
- Thread.cs
- PersonalizationAdministration.cs
- ReadOnlyCollection.cs
- AspProxy.cs
- MulticastNotSupportedException.cs
- CanonicalFontFamilyReference.cs
- SupportsEventValidationAttribute.cs
- BaseCollection.cs
- ModelServiceImpl.cs
- FontFamily.cs
- MD5CryptoServiceProvider.cs
- LocalBuilder.cs
- BuildDependencySet.cs
- TabItemWrapperAutomationPeer.cs
- Utils.cs
- WebRequestModulesSection.cs
- GlobalEventManager.cs
- BooleanConverter.cs
- MemberInfoSerializationHolder.cs
- webeventbuffer.cs
- CommandBindingCollection.cs
- ToolStripSystemRenderer.cs
- HwndKeyboardInputProvider.cs
- ReadOnlyKeyedCollection.cs
- ACE.cs
- FormsAuthenticationEventArgs.cs
- ClosureBinding.cs
- TraceEventCache.cs
- Rect3DConverter.cs
- DiagnosticStrings.cs
- ImportContext.cs
- CheckBox.cs
- SettingsProviderCollection.cs
- TrackingParticipant.cs
- AutoGeneratedField.cs
- NativeConfigurationLoader.cs
- ObjectCache.cs
- PointCollection.cs
- AssemblyBuilder.cs
- StrongNameUtility.cs
- SerializationObjectManager.cs
- TreeViewCancelEvent.cs
- OrderedParallelQuery.cs
- DesignParameter.cs
- XamlSerializerUtil.cs
- RuntimeCompatibilityAttribute.cs
- BindingParameterCollection.cs
- ContainerControl.cs
- StateManagedCollection.cs
- XamlSerializerUtil.cs
- ToolStripButton.cs
- CommandPlan.cs
- BindingParameterCollection.cs
- XmlLanguage.cs
- DataGridViewCellValidatingEventArgs.cs
- EdmProviderManifest.cs
- IncrementalHitTester.cs
- PackageProperties.cs
- ImpersonationContext.cs
- MenuBase.cs
- TransactionChannel.cs
- Exception.cs
- ToolStripSeparatorRenderEventArgs.cs
- GridViewItemAutomationPeer.cs
- AsyncPostBackTrigger.cs
- Bidi.cs
- DesignerInterfaces.cs
- DataTableReaderListener.cs
- OuterGlowBitmapEffect.cs
- GifBitmapDecoder.cs
- ActiveDocumentEvent.cs
- DataGridViewElement.cs
- ScriptControlManager.cs
- GAC.cs
- DataServiceQuery.cs
- FrameworkElementFactoryMarkupObject.cs
- ZipIOZip64EndOfCentralDirectoryBlock.cs
- cryptoapiTransform.cs
- X509Certificate.cs