ConstraintManager.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 / Query / PlanCompiler / ConstraintManager.cs / 3 / ConstraintManager.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System;
using System.Collections.Generic; 
using System.Globalization;
using System.Data.Common;
using System.Data.Query.InternalTrees;
using md=System.Data.Metadata.Edm; 
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
 
// 
// The ConstraintManager module manages foreign key constraints for a query. It reshapes
// referential constraints supplied by metadata into a more useful form. 
//
namespace System.Data.Query.PlanCompiler
{
    ///  
    /// A simple class that represents a pair of extents
    ///  
    internal class ExtentPair 
    {
        #region public surface 
        /// 
        /// Return the left component of the pair
        /// 
        internal md.EntitySetBase Left { get { return m_left; } } 

        ///  
        /// Return the right component of the pair 
        /// 
        internal md.EntitySetBase Right { get { return m_right; } } 

        /// 
        /// Equals
        ///  
        /// 
        ///  
        public override bool Equals(object obj) 
        {
            ExtentPair other = obj as ExtentPair; 
            return (other != null) && other.Left.Equals(this.Left) && other.Right.Equals(this.Right);
        }

        ///  
        /// Hashcode
        ///  
        ///  
        public override int GetHashCode()
        { 
            return (this.Left.GetHashCode() << 4) ^ this.Right.GetHashCode();
        }
        #endregion
 
        #region constructors
        internal ExtentPair(md.EntitySetBase left, md.EntitySetBase right) 
        { 
            m_left = left;
            m_right = right; 
        }
        #endregion

        #region private state 
        private md.EntitySetBase m_left;
        private md.EntitySetBase m_right; 
        #endregion 
    }
 
    /// 
    /// Information about a foreign-key constraint
    /// 
    internal class ForeignKeyConstraint 
    {
        #region public surface 
 
        /// 
        /// Parent key properties 
        /// 
        internal List ParentKeys { get { return m_parentKeys; } }
        /// 
        /// Child key properties 
        /// 
        internal List ChildKeys { get { return m_childKeys; } } 
 
        /// 
        /// Get the parent-child pair 
        /// 
        internal ExtentPair Pair { get { return m_extentPair; } }

        ///  
        /// Return the child rowcount
        ///  
        internal md.RelationshipMultiplicity ChildMultiplicity { get { return m_constraint.ToRole.RelationshipMultiplicity; } } 

        ///  
        /// Get the corresponding parent (key) property, for a specific child (foreign key) property
        /// 
        /// child (foreign key) property name
        /// corresponding parent property name 
        /// true, if the parent property was found
        internal bool GetParentProperty(string childPropertyName, out string parentPropertyName) 
        { 
            BuildKeyMap();
            return m_keyMap.TryGetValue(childPropertyName, out parentPropertyName); 
        }

        /// 
        /// Hash code 
        /// 
        ///  
        public override int GetHashCode() 
        {
            return m_extentPair.GetHashCode(); 
        }
        /// 
        /// Equality check for two FK constraints
        ///  
        /// the other FK constraint
        /// true, if they represent the same object 
        public override bool Equals(object obj) 
        {
            ForeignKeyConstraint other = obj as ForeignKeyConstraint; 
            return other != null && other.m_extentPair.Equals(this.m_extentPair);
        }
        #endregion
 
        #region constructors
        internal ForeignKeyConstraint(md.RelationshipType relType, md.RelationshipSet relationshipSet, md.ReferentialConstraint constraint) 
        { 
            md.AssociationSet assocSet = relationshipSet as md.AssociationSet;
            md.AssociationEndMember fromEnd = constraint.FromRole as md.AssociationEndMember; 
            md.AssociationEndMember toEnd = constraint.ToRole as md.AssociationEndMember;

            // Currently only Associations are supported
            if (null == assocSet || null == fromEnd || null == toEnd) 
            {
                throw EntityUtil.NotSupported(); 
            } 

            m_constraint = constraint; 
            md.EntitySet parent = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, fromEnd);// relationshipSet.GetRelationshipEndExtent(constraint.FromRole);
            md.EntitySet child = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, toEnd);// relationshipSet.GetRelationshipEndExtent(constraint.ToRole);
            m_extentPair = new ExtentPair(parent, child);
            m_childKeys = new List(); 
            foreach (md.EdmProperty prop in constraint.ToProperties)
            { 
                m_childKeys.Add(prop.Name); 
            }
 
            m_parentKeys = new List();
            foreach (md.EdmProperty prop in constraint.FromProperties)
            {
                m_parentKeys.Add(prop.Name); 
            }
 
            PlanCompiler.Assert((md.RelationshipMultiplicity.ZeroOrOne == fromEnd.RelationshipMultiplicity || md.RelationshipMultiplicity.One == fromEnd.RelationshipMultiplicity), "from-end of relationship constraint cannot have multiplicity greater than 1"); 
        }
        #endregion 

        #region private state
        private ExtentPair m_extentPair;
        private List m_parentKeys; 
        private List m_childKeys;
        private md.ReferentialConstraint m_constraint; 
        private Dictionary m_keyMap; 
        #endregion
 
        #region private methods

        /// 
        /// Build up an equivalence map of primary keys and foreign keys (ie) for each 
        /// foreign key column, identify the corresponding primary key property
        ///  
        private void BuildKeyMap() 
        {
            if (m_keyMap != null) 
            {
                return;
            }
 
            m_keyMap = new Dictionary();
            IEnumerator parentProps = m_constraint.FromProperties.GetEnumerator(); 
            IEnumerator childProps = m_constraint.ToProperties.GetEnumerator(); 
            while (true)
            { 
                bool parentOver = !parentProps.MoveNext();
                bool childOver = !childProps.MoveNext();
                PlanCompiler.Assert(parentOver == childOver, "key count mismatch");
                if (parentOver) 
                {
                    break; 
                } 
                m_keyMap[childProps.Current.Name] = parentProps.Current.Name;
            } 
        }
        #endregion
    }
 
    /// 
    /// Keeps track of all foreign key relationships 
    ///  
    internal class ConstraintManager
    { 
        #region public methods
        /// 
        /// Is there a parent child relationship between table1 and table2 ?
        ///  
        /// parent table ?
        /// child table ? 
        /// list of constraints ? 
        /// true if there is at least one constraint
        internal bool IsParentChildRelationship(md.EntitySetBase table1, md.EntitySetBase table2, 
            out List constraints)
        {
            LoadRelationships(table1.EntityContainer);
            LoadRelationships(table2.EntityContainer); 

            ExtentPair extentPair = new ExtentPair(table1, table2); 
            return m_parentChildRelationships.TryGetValue(extentPair, out constraints); 
        }
 
        /// 
        /// Load all relationships in this entity container
        /// 
        ///  
        internal void LoadRelationships(md.EntityContainer entityContainer)
        { 
            // Check to see if I've already loaded information for this entity container 
            if (m_entityContainerMap.ContainsKey(entityContainer))
            { 
                return;
            }

            // Load all relationships from this entitycontainer 
            foreach (md.EntitySetBase e in entityContainer.BaseEntitySets)
            { 
                md.RelationshipSet relationshipSet = e as md.RelationshipSet; 
                if (relationshipSet == null)
                { 
                    continue;
                }

                // Relationship sets can only contain relationships 
                md.RelationshipType relationshipType = (md.RelationshipType)relationshipSet.ElementType;
                md.AssociationType assocType = relationshipType as md.AssociationType; 
 
                //
                // Handle only binary Association relationships for now 
                //
                if (null == assocType || !IsBinary(relationshipType))
                {
                    continue; 
                }
 
                foreach (md.ReferentialConstraint constraint in assocType.ReferentialConstraints) 
                {
                    List fkConstraintList; 
                    ForeignKeyConstraint fkConstraint = new ForeignKeyConstraint(relationshipType, relationshipSet, constraint);
                    if (!m_parentChildRelationships.TryGetValue(fkConstraint.Pair, out fkConstraintList))
                    {
                        fkConstraintList = new List(); 
                        m_parentChildRelationships[fkConstraint.Pair] = fkConstraintList;
                    } 
                    // 
                    // Theoretically, we can have more than one fk constraint between
                    // the 2 tables (though, it is unlikely) 
                    //
                    fkConstraintList.Add(fkConstraint);
                }
            } 

            // Mark this entity container as already loaded 
            m_entityContainerMap[entityContainer] = entityContainer; 
        }
        #endregion 

        #region constructors
        internal ConstraintManager()
        { 
            m_entityContainerMap = new Dictionary();
            m_parentChildRelationships = new Dictionary>(); 
        } 
        #endregion
 
        #region private state
        private Dictionary m_entityContainerMap;
        private Dictionary> m_parentChildRelationships;
        #endregion 

        #region private methods 
 
        /// 
        /// Is this relationship a binary relationship (ie) does it have exactly 2 end points? 
        ///
        /// This should ideally be a method supported by RelationType itself
        /// 
        ///  
        /// true, if this is a binary relationship
        private static bool IsBinary(md.RelationshipType relationshipType) 
        { 
            int endCount = 0;
            foreach(md.EdmMember member in relationshipType.Members) 
            {
                if (member is md.RelationshipEndMember)
                {
                    endCount++; 
                    if (endCount > 2)
                    { 
                        return false; 
                    }
                } 
            }
            return (endCount == 2);
        }
        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System;
using System.Collections.Generic; 
using System.Globalization;
using System.Data.Common;
using System.Data.Query.InternalTrees;
using md=System.Data.Metadata.Edm; 
//using System.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
 
// 
// The ConstraintManager module manages foreign key constraints for a query. It reshapes
// referential constraints supplied by metadata into a more useful form. 
//
namespace System.Data.Query.PlanCompiler
{
    ///  
    /// A simple class that represents a pair of extents
    ///  
    internal class ExtentPair 
    {
        #region public surface 
        /// 
        /// Return the left component of the pair
        /// 
        internal md.EntitySetBase Left { get { return m_left; } } 

        ///  
        /// Return the right component of the pair 
        /// 
        internal md.EntitySetBase Right { get { return m_right; } } 

        /// 
        /// Equals
        ///  
        /// 
        ///  
        public override bool Equals(object obj) 
        {
            ExtentPair other = obj as ExtentPair; 
            return (other != null) && other.Left.Equals(this.Left) && other.Right.Equals(this.Right);
        }

        ///  
        /// Hashcode
        ///  
        ///  
        public override int GetHashCode()
        { 
            return (this.Left.GetHashCode() << 4) ^ this.Right.GetHashCode();
        }
        #endregion
 
        #region constructors
        internal ExtentPair(md.EntitySetBase left, md.EntitySetBase right) 
        { 
            m_left = left;
            m_right = right; 
        }
        #endregion

        #region private state 
        private md.EntitySetBase m_left;
        private md.EntitySetBase m_right; 
        #endregion 
    }
 
    /// 
    /// Information about a foreign-key constraint
    /// 
    internal class ForeignKeyConstraint 
    {
        #region public surface 
 
        /// 
        /// Parent key properties 
        /// 
        internal List ParentKeys { get { return m_parentKeys; } }
        /// 
        /// Child key properties 
        /// 
        internal List ChildKeys { get { return m_childKeys; } } 
 
        /// 
        /// Get the parent-child pair 
        /// 
        internal ExtentPair Pair { get { return m_extentPair; } }

        ///  
        /// Return the child rowcount
        ///  
        internal md.RelationshipMultiplicity ChildMultiplicity { get { return m_constraint.ToRole.RelationshipMultiplicity; } } 

        ///  
        /// Get the corresponding parent (key) property, for a specific child (foreign key) property
        /// 
        /// child (foreign key) property name
        /// corresponding parent property name 
        /// true, if the parent property was found
        internal bool GetParentProperty(string childPropertyName, out string parentPropertyName) 
        { 
            BuildKeyMap();
            return m_keyMap.TryGetValue(childPropertyName, out parentPropertyName); 
        }

        /// 
        /// Hash code 
        /// 
        ///  
        public override int GetHashCode() 
        {
            return m_extentPair.GetHashCode(); 
        }
        /// 
        /// Equality check for two FK constraints
        ///  
        /// the other FK constraint
        /// true, if they represent the same object 
        public override bool Equals(object obj) 
        {
            ForeignKeyConstraint other = obj as ForeignKeyConstraint; 
            return other != null && other.m_extentPair.Equals(this.m_extentPair);
        }
        #endregion
 
        #region constructors
        internal ForeignKeyConstraint(md.RelationshipType relType, md.RelationshipSet relationshipSet, md.ReferentialConstraint constraint) 
        { 
            md.AssociationSet assocSet = relationshipSet as md.AssociationSet;
            md.AssociationEndMember fromEnd = constraint.FromRole as md.AssociationEndMember; 
            md.AssociationEndMember toEnd = constraint.ToRole as md.AssociationEndMember;

            // Currently only Associations are supported
            if (null == assocSet || null == fromEnd || null == toEnd) 
            {
                throw EntityUtil.NotSupported(); 
            } 

            m_constraint = constraint; 
            md.EntitySet parent = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, fromEnd);// relationshipSet.GetRelationshipEndExtent(constraint.FromRole);
            md.EntitySet child = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, toEnd);// relationshipSet.GetRelationshipEndExtent(constraint.ToRole);
            m_extentPair = new ExtentPair(parent, child);
            m_childKeys = new List(); 
            foreach (md.EdmProperty prop in constraint.ToProperties)
            { 
                m_childKeys.Add(prop.Name); 
            }
 
            m_parentKeys = new List();
            foreach (md.EdmProperty prop in constraint.FromProperties)
            {
                m_parentKeys.Add(prop.Name); 
            }
 
            PlanCompiler.Assert((md.RelationshipMultiplicity.ZeroOrOne == fromEnd.RelationshipMultiplicity || md.RelationshipMultiplicity.One == fromEnd.RelationshipMultiplicity), "from-end of relationship constraint cannot have multiplicity greater than 1"); 
        }
        #endregion 

        #region private state
        private ExtentPair m_extentPair;
        private List m_parentKeys; 
        private List m_childKeys;
        private md.ReferentialConstraint m_constraint; 
        private Dictionary m_keyMap; 
        #endregion
 
        #region private methods

        /// 
        /// Build up an equivalence map of primary keys and foreign keys (ie) for each 
        /// foreign key column, identify the corresponding primary key property
        ///  
        private void BuildKeyMap() 
        {
            if (m_keyMap != null) 
            {
                return;
            }
 
            m_keyMap = new Dictionary();
            IEnumerator parentProps = m_constraint.FromProperties.GetEnumerator(); 
            IEnumerator childProps = m_constraint.ToProperties.GetEnumerator(); 
            while (true)
            { 
                bool parentOver = !parentProps.MoveNext();
                bool childOver = !childProps.MoveNext();
                PlanCompiler.Assert(parentOver == childOver, "key count mismatch");
                if (parentOver) 
                {
                    break; 
                } 
                m_keyMap[childProps.Current.Name] = parentProps.Current.Name;
            } 
        }
        #endregion
    }
 
    /// 
    /// Keeps track of all foreign key relationships 
    ///  
    internal class ConstraintManager
    { 
        #region public methods
        /// 
        /// Is there a parent child relationship between table1 and table2 ?
        ///  
        /// parent table ?
        /// child table ? 
        /// list of constraints ? 
        /// true if there is at least one constraint
        internal bool IsParentChildRelationship(md.EntitySetBase table1, md.EntitySetBase table2, 
            out List constraints)
        {
            LoadRelationships(table1.EntityContainer);
            LoadRelationships(table2.EntityContainer); 

            ExtentPair extentPair = new ExtentPair(table1, table2); 
            return m_parentChildRelationships.TryGetValue(extentPair, out constraints); 
        }
 
        /// 
        /// Load all relationships in this entity container
        /// 
        ///  
        internal void LoadRelationships(md.EntityContainer entityContainer)
        { 
            // Check to see if I've already loaded information for this entity container 
            if (m_entityContainerMap.ContainsKey(entityContainer))
            { 
                return;
            }

            // Load all relationships from this entitycontainer 
            foreach (md.EntitySetBase e in entityContainer.BaseEntitySets)
            { 
                md.RelationshipSet relationshipSet = e as md.RelationshipSet; 
                if (relationshipSet == null)
                { 
                    continue;
                }

                // Relationship sets can only contain relationships 
                md.RelationshipType relationshipType = (md.RelationshipType)relationshipSet.ElementType;
                md.AssociationType assocType = relationshipType as md.AssociationType; 
 
                //
                // Handle only binary Association relationships for now 
                //
                if (null == assocType || !IsBinary(relationshipType))
                {
                    continue; 
                }
 
                foreach (md.ReferentialConstraint constraint in assocType.ReferentialConstraints) 
                {
                    List fkConstraintList; 
                    ForeignKeyConstraint fkConstraint = new ForeignKeyConstraint(relationshipType, relationshipSet, constraint);
                    if (!m_parentChildRelationships.TryGetValue(fkConstraint.Pair, out fkConstraintList))
                    {
                        fkConstraintList = new List(); 
                        m_parentChildRelationships[fkConstraint.Pair] = fkConstraintList;
                    } 
                    // 
                    // Theoretically, we can have more than one fk constraint between
                    // the 2 tables (though, it is unlikely) 
                    //
                    fkConstraintList.Add(fkConstraint);
                }
            } 

            // Mark this entity container as already loaded 
            m_entityContainerMap[entityContainer] = entityContainer; 
        }
        #endregion 

        #region constructors
        internal ConstraintManager()
        { 
            m_entityContainerMap = new Dictionary();
            m_parentChildRelationships = new Dictionary>(); 
        } 
        #endregion
 
        #region private state
        private Dictionary m_entityContainerMap;
        private Dictionary> m_parentChildRelationships;
        #endregion 

        #region private methods 
 
        /// 
        /// Is this relationship a binary relationship (ie) does it have exactly 2 end points? 
        ///
        /// This should ideally be a method supported by RelationType itself
        /// 
        ///  
        /// true, if this is a binary relationship
        private static bool IsBinary(md.RelationshipType relationshipType) 
        { 
            int endCount = 0;
            foreach(md.EdmMember member in relationshipType.Members) 
            {
                if (member is md.RelationshipEndMember)
                {
                    endCount++; 
                    if (endCount > 2)
                    { 
                        return false; 
                    }
                } 
            }
            return (endCount == 2);
        }
        #endregion 
    }
} 

// 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