KeyManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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 IEnumerable GetDependentStateEntries(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 IEnumerable GetPrincipals(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. 
            Dictionary color = 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 IEnumerable GetPath()
            { 
                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 IEnumerable GetDependentStateEntries(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 IEnumerable GetPrincipals(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. 
            Dictionary color = 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 IEnumerable GetPath()
            { 
                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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK