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
- SecurityTokenSpecification.cs
- XmlValidatingReaderImpl.cs
- Vector.cs
- UITypeEditor.cs
- AspNetRouteServiceHttpHandler.cs
- GatewayDefinition.cs
- OleDbReferenceCollection.cs
- StructuredProperty.cs
- KnownBoxes.cs
- SqlInfoMessageEvent.cs
- Preprocessor.cs
- HebrewNumber.cs
- Setter.cs
- StrongTypingException.cs
- DataSourceCollectionBase.cs
- ProtocolViolationException.cs
- CodeSubDirectory.cs
- PageAsyncTask.cs
- DataGridViewCellStyle.cs
- StateWorkerRequest.cs
- IncrementalReadDecoders.cs
- SoapClientMessage.cs
- EdmItemCollection.OcAssemblyCache.cs
- BamlRecordHelper.cs
- RuntimeWrappedException.cs
- ObjectConverter.cs
- InkPresenterAutomationPeer.cs
- DetailsViewDeleteEventArgs.cs
- ArcSegment.cs
- SoapObjectWriter.cs
- FullTextLine.cs
- XhtmlTextWriter.cs
- PathFigureCollectionValueSerializer.cs
- EtwTrace.cs
- SqlConnectionPoolGroupProviderInfo.cs
- SecurityCriticalDataForSet.cs
- _HeaderInfo.cs
- NonVisualControlAttribute.cs
- TriggerActionCollection.cs
- GridViewDeletedEventArgs.cs
- Thread.cs
- AbstractDataSvcMapFileLoader.cs
- SignatureTargetIdManager.cs
- HttpListener.cs
- Error.cs
- ContourSegment.cs
- VectorValueSerializer.cs
- Visual.cs
- Win32.cs
- InvalidDataException.cs
- HttpClientCertificate.cs
- DataGridViewColumnConverter.cs
- AssemblySettingAttributes.cs
- DriveInfo.cs
- CodeDomDecompiler.cs
- WebBrowserNavigatedEventHandler.cs
- ModelTypeConverter.cs
- DataGridViewRowsRemovedEventArgs.cs
- VerifyHashRequest.cs
- NavigationHelper.cs
- HashCodeCombiner.cs
- TileModeValidation.cs
- ListControlConvertEventArgs.cs
- ContainerFilterService.cs
- ReliabilityContractAttribute.cs
- SchemaElementDecl.cs
- SecurityPermission.cs
- SymmetricAlgorithm.cs
- SemanticResultKey.cs
- FindResponse.cs
- Profiler.cs
- DataGridItemCollection.cs
- NodeInfo.cs
- SafeMILHandleMemoryPressure.cs
- WebResponse.cs
- StaticFileHandler.cs
- QueryCacheKey.cs
- ValidatingReaderNodeData.cs
- DataGridPageChangedEventArgs.cs
- CompositeFontParser.cs
- SafeNativeMethods.cs
- ListControl.cs
- SqlInternalConnection.cs
- DocumentAutomationPeer.cs
- WebBrowserSiteBase.cs
- BindingGraph.cs
- EntitySetBase.cs
- PointLight.cs
- TreeView.cs
- DesignerWidgets.cs
- EntryIndex.cs
- DataGridPageChangedEventArgs.cs
- TemplateLookupAction.cs
- SocketInformation.cs
- DesignerActionVerbItem.cs
- RemoteEndpointMessageProperty.cs
- DockingAttribute.cs
- CapiSafeHandles.cs
- RequestStatusBarUpdateEventArgs.cs
- ItemsPresenter.cs