DataRelation.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Data / System / Data / DataRelation.cs / 1 / DataRelation.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
// [....] 
//----------------------------------------------------------------------------- 

/***************************************************************************************************** 
Rules for Multiple Nested Parent, enforce following constraints

1) At all times, only 1(ONE) FK can be NON-Null in a row.
2) NULL FK values are not associated with PARENT(x), even if if PK is NULL in Parent 
3) Enforce  when
        a) Any FK value is changed 
        b) A relation created that result in Multiple Nested Child 

WriteXml 

1) WriteXml will throw if  is violated
2) if NON-Null FK has parentRow (boolean check) print as Nested, else it will get written as normal row
 
additional notes:
We decided to enforce the rule 1 just if Xml being persisted 
******************************************************************************************************/ 

namespace System.Data { 
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Data.Common;
    using System.Collections.Generic; 
 
    /// 
    ///     
    ///       Represents a parent/child relationship between two tables.
    ///    
    /// 
    [ 
    DefaultProperty("RelationName"),
    Editor("Microsoft.VSDesigner.Data.Design.DataRelationEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing), 
    TypeConverter(typeof(RelationshipConverter)), 
    ]
#if WINFSInternalOnly 
    internal
#else
    public
#endif 
    class DataRelation {
 
        // properties 
        private DataSet dataSet    = null;
        internal PropertyCollection extendedProperties = null; 
        internal string relationName   = "";

        // events
        private PropertyChangedEventHandler onPropertyChangingDelegate = null; 

        // state 
        private DataKey childKey; 
        private DataKey parentKey;
        private UniqueConstraint parentKeyConstraint = null; 
        private ForeignKeyConstraint childKeyConstraint = null;

        // Design time serialization
        internal string[] parentColumnNames = null; 
        internal string[] childColumnNames = null;
        internal string parentTableName = null; 
        internal string childTableName = null; 
        internal string parentTableNamespace= null;
        internal string childTableNamespace = null; 

        /// 
        /// this stores whether the  child element appears beneath the parent in the XML persised files.
        ///  
        internal bool nested = false;
 
        ///  
        /// this stores whether the the relationship should make sure that KeyConstraints and ForeignKeyConstraints
        /// exist when added to the ConstraintsCollections of the table. 
        /// 
        internal bool createConstraints;

        private bool _checkMultipleNested = true; 

        private static int _objectTypeCount; // Bid counter 
        private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        ///    
        ///       Initializes a new instance of the  class using the specified name,
        ///       parent, and child columns.
        ///     
        /// 
        public DataRelation(string relationName, DataColumn parentColumn, DataColumn childColumn) 
        : this(relationName, parentColumn, childColumn, true) { 
        }
 
        /// 
        ///    
        ///       Initializes a new instance of the  class using the specified name, parent, and child columns, and
        ///       value to create constraints. 
        ///    
        ///  
        public DataRelation(string relationName, DataColumn parentColumn, DataColumn childColumn, bool createConstraints) { 
            Bid.Trace(" %d#, relationName='%ls', parentColumn=%d, childColumn=%d, createConstraints=%d{bool}\n",
                            ObjectID, relationName, (parentColumn != null) ? parentColumn.ObjectID : 0, (childColumn != null) ? childColumn.ObjectID : 0, 
                            createConstraints);

            DataColumn[] parentColumns = new DataColumn[1];
            parentColumns[0] = parentColumn; 
            DataColumn[] childColumns = new DataColumn[1];
            childColumns[0] = childColumn; 
            Create(relationName, parentColumns, childColumns, createConstraints); 
        }
 
        /// 
        ///    
        ///       Initializes a new instance of the  class using the specified name
        ///       and matched arrays of parent and child columns. 
        ///    
        ///  
        public DataRelation(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns) 
        : this(relationName, parentColumns, childColumns, true) {
        } 

        /// 
        ///    
        ///       Initializes a new instance of the  class using the specified name, matched arrays of parent 
        ///       and child columns, and value to create constraints.
        ///     
        ///  
        public DataRelation(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints) {
            Create(relationName, parentColumns, childColumns, createConstraints); 
        }

        // Design time constructor
        ///  
        ///    [To be supplied.]
        ///  
        [Browsable(false)] 
        public DataRelation(string relationName, string parentTableName, string childTableName, string[] parentColumnNames, string[] childColumnNames, bool nested) {
            this.relationName = relationName; 
            this.parentColumnNames = parentColumnNames;
            this.childColumnNames = childColumnNames;
            this.parentTableName = parentTableName;
            this.childTableName = childTableName; 
            this.nested = nested;
            // DataRelation(relationName, parentTableName, null, childTableName, null, parentColumnNames, childColumnNames, nested) 
        } 

        [Browsable(false)] 
        // Design time constructor
        public DataRelation(string relationName, string parentTableName, string parentTableNamespace, string childTableName, string childTableNamespace, string[] parentColumnNames, string[] childColumnNames, bool nested) {
            this.relationName = relationName;
            this.parentColumnNames = parentColumnNames; 
            this.childColumnNames = childColumnNames;
            this.parentTableName = parentTableName; 
            this.childTableName = childTableName; 
            this.parentTableNamespace = parentTableNamespace;
            this.childTableNamespace = childTableNamespace; 
            this.nested = nested;
        }

        ///  
        ///    
        ///       Gets the child columns of this relation. 
        ///     
        /// 
        [ 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataRelationChildColumnsDescr)
        ]
        public virtual DataColumn[] ChildColumns { 
            get {
                CheckStateForProperty(); 
                return childKey.ToArray(); 
            }
        } 

        internal DataColumn[] ChildColumnsReference {
            get {
                CheckStateForProperty(); 
                return childKey.ColumnsReference;
            } 
        } 

        ///  
        /// The internal Key object for the child table.
        /// 
        internal DataKey ChildKey {
            get { 
                CheckStateForProperty();
                return childKey; 
            } 
        }
 
        /// 
        ///    
        ///       Gets the child table of this relation.
        ///     
        /// 
        public virtual DataTable ChildTable { 
            get { 
                CheckStateForProperty();
                return childKey.Table; 
            }
        }

        ///  
        ///    
        ///       Gets the  to which the relations' collection belongs to. 
        ///     
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)] 
        public virtual DataSet DataSet {
            get {
                CheckStateForProperty();
                return dataSet; 
            }
        } 
 
        internal string[] ParentColumnNames {
            get { 
                return parentKey.GetColumnNames();
            }
        }
 
        internal string[] ChildColumnNames {
            get { 
                return childKey.GetColumnNames(); 
            }
        } 

        private static bool IsKeyNull(object[] values) {
            for (int i = 0; i < values.Length; i++) {
                if (!DataStorage.IsObjectNull(values[i])) 
                    return false;
            } 
 
            return true;
        } 

        /// 
        /// Gets the child rows for the parent row across the relation using the version given
        ///  
        internal static DataRow[] GetChildRows(DataKey parentKey, DataKey childKey, DataRow parentRow, DataRowVersion version) {
            object[] values = parentRow.GetKeyValues(parentKey, version); 
            if (IsKeyNull(values)) { 
                return childKey.Table.NewRowArray(0);
            } 

            Index index = childKey.GetSortIndex((version == DataRowVersion.Original) ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows);
            return index.GetRows(values);
        } 

        ///  
        /// Gets the parent rows for the given child row across the relation using the version given 
        /// 
        internal static DataRow[] GetParentRows(DataKey parentKey, DataKey childKey, DataRow childRow, DataRowVersion version) { 
            object[] values = childRow.GetKeyValues(childKey, version);
            if (IsKeyNull(values)) {
                return parentKey.Table.NewRowArray(0);
            } 

            Index index = parentKey.GetSortIndex((version == DataRowVersion.Original) ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows); 
            return index.GetRows(values); 
        }
 
        internal static DataRow GetParentRow(DataKey parentKey, DataKey childKey, DataRow childRow, DataRowVersion version) {
            if (!childRow.HasVersion((version == DataRowVersion.Original) ? DataRowVersion.Original : DataRowVersion.Current))
                if (childRow.tempRecord == -1)
                    return null; 

            object[] values = childRow.GetKeyValues(childKey, version); 
            if (IsKeyNull(values)) { 
                return null;
            } 

            Index index = parentKey.GetSortIndex((version == DataRowVersion.Original) ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows);
            Range range = index.FindRecords(values);
            if (range.IsNull) { 
                return null;
            } 
 
            if (range.Count > 1) {
                throw ExceptionBuilder.MultipleParents(); 
            }
            return parentKey.Table.recordManager[index.GetRecord(range.Min)];
        }
 

        ///  
        /// Internally sets the DataSet pointer. 
        /// 
        internal void SetDataSet(DataSet dataSet) { 
            if (this.dataSet != dataSet) {
                this.dataSet = dataSet;
            }
        } 

        internal void SetParentRowRecords(DataRow childRow, DataRow parentRow) { 
            object[] parentKeyValues = parentRow.GetKeyValues(ParentKey); 
            if (childRow.tempRecord != -1) {
                ChildTable.recordManager.SetKeyValues(childRow.tempRecord, ChildKey, parentKeyValues); 
            }
            if (childRow.newRecord != -1) {
                ChildTable.recordManager.SetKeyValues(childRow.newRecord, ChildKey, parentKeyValues);
            } 
            if (childRow.oldRecord != -1) {
                ChildTable.recordManager.SetKeyValues(childRow.oldRecord, ChildKey, parentKeyValues); 
            } 
        }
 
        /// 
        ///    
        ///       Gets the parent columns of this relation.
        ///     
        /// 
        [ 
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataRelationParentColumnsDescr)
        ] 
        public virtual DataColumn[] ParentColumns {
            get {
                CheckStateForProperty();
                return parentKey.ToArray(); 
            }
        } 
 
        internal DataColumn[] ParentColumnsReference {
            get { 
                return parentKey.ColumnsReference;
            }
        }
 
        /// 
        /// The internal constraint object for the parent table. 
        ///  
        internal DataKey ParentKey {
            get { 
                CheckStateForProperty();
                return parentKey;
            }
        } 

        ///  
        ///     
        ///       Gets the parent table of this relation.
        ///     
        /// 
        public virtual DataTable ParentTable {
            get {
                CheckStateForProperty(); 
                return parentKey.Table;
            } 
        } 

        ///  
        ///    
        ///       Gets or sets
        ///       the name used to look up this relation in the parent
        ///       data set's . 
        ///    
        ///  
        [ 
        ResCategoryAttribute(Res.DataCategory_Data),
        DefaultValue(""), 
        ResDescriptionAttribute(Res.DataRelationRelationNameDescr)
        ]
        public virtual string RelationName {
            get { 
                CheckStateForProperty();
                return relationName; 
            } 
            set {
                IntPtr hscp; 
                Bid.ScopeEnter(out hscp, " %d#, '%ls'\n", ObjectID, value);
                try {
                    if (value == null)
                        value = ""; 

                    CultureInfo locale = (dataSet != null ? dataSet.Locale : CultureInfo.CurrentCulture); 
                    if (String.Compare(relationName, value, true, locale) != 0) { 
                        if (dataSet != null) {
                            if (value.Length == 0) 
                                throw ExceptionBuilder.NoRelationName();
                            dataSet.Relations.RegisterName(value);
                            if (relationName.Length != 0)
                                dataSet.Relations.UnregisterName(relationName); 
                        }
                        this.relationName = value; 
                        ((DataRelationCollection.DataTableRelationCollection)(ParentTable.ChildRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this)); 
                        ((DataRelationCollection.DataTableRelationCollection)(ChildTable.ParentRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this));
                    } 
                    else if (String.Compare(relationName, value, false, locale) != 0) {
                        relationName = value;
                        ((DataRelationCollection.DataTableRelationCollection)(ParentTable.ChildRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this));
                        ((DataRelationCollection.DataTableRelationCollection)(ChildTable.ParentRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this)); 
                    }
                } 
                finally{ 
                    Bid.ScopeLeave(ref hscp);
                } 
            }
        }
        internal void CheckNamespaceValidityForNestedRelations(string ns) {
            foreach(DataRelation rel in ChildTable.ParentRelations) { 
                if (rel == this || rel.Nested) {
                    if (rel.ParentTable.Namespace != ns) { 
                        throw ExceptionBuilder.InValidNestedRelation(ChildTable.TableName); 
                    }
                } 
            }
        }

        internal void CheckNestedRelations() { 
            Bid.Trace(" %d#\n", ObjectID);
 
            Debug.Assert(DataSet == null || ! nested, "this relation supposed to be not in dataset or not nested"); 
            // 1. There is no other relation (R) that has this.ChildTable as R.ChildTable
            //  This is not valid for Whidbey anymore so the code has been removed 

            // 2. There is no loop in nested relations
#if DEBUG
            int numTables = ParentTable.DataSet.Tables.Count; 
#endif
            DataTable dt = ParentTable; 
 
            if (ChildTable == ParentTable){
                if (String.Compare(ChildTable.TableName, ChildTable.DataSet.DataSetName, true, ChildTable.DataSet.Locale) == 0) 
                   throw ExceptionBuilder.SelfnestedDatasetConflictingName(ChildTable.TableName);
                return; //allow self join tables.
            }
 
            List list = new List();
            list.Add(ChildTable); 
 
            // We have already checked for nested relaion UP
            for(int i = 0; i < list.Count; ++i) { 
                DataRelation[] relations = list[i].NestedParentRelations;
                foreach(DataRelation rel in relations) {
                    if (rel.ParentTable == ChildTable && rel.ChildTable != ChildTable) {
                        throw ExceptionBuilder.LoopInNestedRelations(ChildTable.TableName); 
                    }
                    if (!list.Contains (rel.ParentTable)) { // check for self nested 
                        list.Add(rel.ParentTable); 
                    }
                } 
            }
        }
        /********************
          The Namespace of a table nested inside multiple parents can be 
          1. Explicitly specified
          2. Inherited from Parent Table 
          3. Empty (Form = unqualified case) 
          However, Schema does not allow (3) to be a global element and multiple nested child has to be a global element.
          Therefore we'll reduce case (3) to (2) if all parents have same namespace else throw. 
         ********************/
        /// 
        ///    
        ///       Gets or sets a value indicating whether relations are nested. 
        ///    
        ///  
        [ 
        ResCategoryAttribute(Res.DataCategory_Data),
        DefaultValue(false), 
        ResDescriptionAttribute(Res.DataRelationNested)
        ]
        public virtual bool Nested {
            get { 
                CheckStateForProperty();
                return nested; 
            } 
            set {
                IntPtr hscp; 
                Bid.ScopeEnter(out hscp, " %d#, %d{bool}\n", ObjectID, value);
                try {
                    if (nested != value) {
                        if (dataSet != null) { 
                            if (value) {
                                if (ChildTable.IsNamespaceInherited()) { // if not added to collection, don't do this check 
                                    CheckNamespaceValidityForNestedRelations(ParentTable.Namespace); 
                                }
                                Debug.Assert(ChildTable != null, "On a DataSet, but not on Table. Bad state"); 
                                ForeignKeyConstraint constraint = ChildTable.Constraints.FindForeignKeyConstraint(ChildKey.ColumnsReference, ParentKey.ColumnsReference);
                                if (constraint != null) {
                                    constraint.CheckConstraint();
                                } 
                                ValidateMultipleNestedRelations();
                            } 
                        } 
                        if (!value && (parentKey.ColumnsReference[0].ColumnMapping == MappingType.Hidden))
                            throw ExceptionBuilder.RelationNestedReadOnly(); 

                        if (value) {
                          this.ParentTable.Columns.RegisterColumnName(this.ChildTable.TableName, (DataColumn)null, this.ChildTable);
                        } else { 
                          this.ParentTable.Columns.UnregisterName(this.ChildTable.TableName);
                        } 
                        RaisePropertyChanging("Nested"); 

                        if(value) { 
                            CheckNestedRelations();
                            if (this.DataSet != null)
                                if (ParentTable == ChildTable) {
                                    foreach(DataRow row in ChildTable.Rows) 
                                        row.CheckForLoops(this);
 
                                    if (ChildTable.DataSet != null && ( String.Compare(ChildTable.TableName, ChildTable.DataSet.DataSetName, true, ChildTable.DataSet.Locale) == 0) ) 
                                        throw ExceptionBuilder.DatasetConflictingName(dataSet.DataSetName);
                                    ChildTable.fNestedInDataset = false; 
                                }
                                else {
                                        foreach(DataRow row in ChildTable.Rows)
                                            row.GetParentRow(this); 
                                }
 
                            this.ParentTable.ElementColumnCount++; 
                        }
                        else { 
                            this.ParentTable.ElementColumnCount--;
                        }

                        this.nested = value; 
                        ChildTable.CacheNestedParent();
                        if (value) { 
                            if (ADP.IsEmpty(ChildTable.Namespace) && ((ChildTable.NestedParentsCount > 1) || 
                                ((ChildTable.NestedParentsCount > 0) && ! (ChildTable.DataSet.Relations.Contains(this.RelationName))))) {
                                string parentNs = null; 
                                foreach(DataRelation rel in ChildTable.ParentRelations) {
                                    if (rel.Nested) {
                                        if (null == parentNs) {
                                            parentNs = rel.ParentTable.Namespace; 
                                        }
                                        else { 
                                            if (String.Compare(parentNs, rel.ParentTable.Namespace, StringComparison.Ordinal) != 0) { 
                                                this.nested = false;
                                                throw ExceptionBuilder.InvalidParentNamespaceinNestedRelation(ChildTable.TableName); 
                                            }
                                        }
                                    }
                                } 
                                // if not already in memory , form == unqualified
                                if (CheckMultipleNested && ChildTable.tableNamespace != null && ChildTable.tableNamespace.Length == 0) { 
                                    throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName); 
                                }
                                ChildTable.tableNamespace = null; // if we dont throw, then let it inherit the Namespace 
                            }
                        }
                    }
                } 
                finally{
                    Bid.ScopeLeave(ref hscp); 
                } 
            }
        } 

        /// 
        ///    
        ///       Gets the constraint which ensures values in a column are unique. 
        ///    
        ///  
        public virtual UniqueConstraint ParentKeyConstraint { 
            get {
                CheckStateForProperty(); 
                return parentKeyConstraint;
            }
        }
 
        internal void SetParentKeyConstraint(UniqueConstraint value) {
            Debug.Assert(parentKeyConstraint == null || value == null, "ParentKeyConstraint should not have been set already."); 
            parentKeyConstraint = value; 
        }
 

        /// 
        ///    
        ///       Gets the  for the relation. 
        ///    
        ///  
        public virtual ForeignKeyConstraint ChildKeyConstraint { 
            get {
                CheckStateForProperty(); 
                return childKeyConstraint;
            }
        }
 
        /// 
        ///    Gets the collection of custom user information. 
        ///  
        [
        ResCategoryAttribute(Res.DataCategory_Data), 
        Browsable(false),
        ResDescriptionAttribute(Res.ExtendedPropertiesDescr)
        ]
        public PropertyCollection ExtendedProperties { 
            get {
                if (extendedProperties == null) { 
                    extendedProperties = new PropertyCollection(); 
                }
                return extendedProperties; 
            }
        }

        internal bool CheckMultipleNested { 
            get {
                return _checkMultipleNested; 
            } 
            set {
                _checkMultipleNested = value; 
            }
        }

        internal void SetChildKeyConstraint(ForeignKeyConstraint value) { 
            Debug.Assert(childKeyConstraint == null || value == null, "ChildKeyConstraint should not have been set already.");
            childKeyConstraint = value; 
        } 

        internal event PropertyChangedEventHandler PropertyChanging { 
            add {
                onPropertyChangingDelegate += value;
            }
            remove { 
                onPropertyChangingDelegate -= value;
            } 
        } 
        // If we're not in a dataSet relations collection, we need to verify on every property get that we're
        // still a good relation object. 
        internal void CheckState() {
            if (dataSet == null) {
                parentKey.CheckState();
                childKey.CheckState(); 

                if (parentKey.Table.DataSet != childKey.Table.DataSet) { 
                    throw ExceptionBuilder.RelationDataSetMismatch(); 
                }
 
                if (childKey.ColumnsEqual(parentKey)) {
                    throw ExceptionBuilder.KeyColumnsIdentical();
                }
 
                for (int i = 0; i < parentKey.ColumnsReference.Length; i++) {
                    if ((parentKey.ColumnsReference[i].DataType != childKey.ColumnsReference[i].DataType) || 
                        ((parentKey.ColumnsReference[i].DataType ==  typeof(DateTime)) && 
                        (parentKey.ColumnsReference[i].DateTimeMode != childKey.ColumnsReference[i].DateTimeMode) &&
                        ((parentKey.ColumnsReference[i].DateTimeMode & childKey.ColumnsReference[i].DateTimeMode) != DataSetDateTime.Unspecified))) 
                        // alow unspecified and unspecifiedlocal
                        throw ExceptionBuilder.ColumnsTypeMismatch();
                }
            } 
        }
 
        ///  
        ///    Checks to ensure the DataRelation is a valid object, even if it doesn't
        ///       belong to a . 
        /// 
        protected void CheckStateForProperty() {
            try {
                CheckState(); 
            }
            catch (Exception e) { 
                // 
                if (ADP.IsCatchableExceptionType(e)) {
                    throw ExceptionBuilder.BadObjectPropertyAccess(e.Message); 
                }
                throw;
            }
        } 

        private void Create(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints) { 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, relationName='%ls', createConstraints=%d{bool}\n",
                               ObjectID, relationName, createConstraints); 
            try {
                this.parentKey = new DataKey(parentColumns, true);
                this.childKey = new DataKey(childColumns, true);
 
                if (parentColumns.Length != childColumns.Length)
                    throw ExceptionBuilder.KeyLengthMismatch(); 
 
                for(int i = 0; i < parentColumns.Length; i++){
                    if ((parentColumns[i].Table.DataSet == null) || (childColumns[i].Table.DataSet == null)) 
                        throw ExceptionBuilder.ParentOrChildColumnsDoNotHaveDataSet();
                }

                CheckState(); 

                this.relationName = (relationName == null ? "" : relationName); 
                this.createConstraints = createConstraints; 
            }
            finally{ 
                Bid.ScopeLeave(ref hscp);
            }
        }
 

        internal DataRelation Clone(DataSet destination) { 
            Bid.Trace(" %d#, destination=%d\n", ObjectID, (destination != null) ? destination.ObjectID : 0); 

            DataTable parent = destination.Tables[ParentTable.TableName, ParentTable.Namespace]; 
            DataTable child = destination.Tables[ChildTable.TableName, ChildTable.Namespace];
            int keyLength = parentKey.ColumnsReference.Length;

            DataColumn[] parentColumns = new DataColumn[keyLength]; 
            DataColumn[] childColumns = new DataColumn[keyLength];
 
            for (int i = 0; i < keyLength; i++) { 
                parentColumns[i] = parent.Columns[ParentKey.ColumnsReference[i].ColumnName];
                childColumns[i] = child.Columns[ChildKey.ColumnsReference[i].ColumnName]; 
            }

            DataRelation clone = new DataRelation(relationName, parentColumns, childColumns, false);
 
            clone.CheckMultipleNested = false; // disable the check  in clone as it is already created
            clone.Nested = this.Nested; 
            clone.CheckMultipleNested = true; // enable the check 

            // ...Extended Properties 
            if (this.extendedProperties != null) {
                foreach(Object key in this.extendedProperties.Keys) {
                    clone.ExtendedProperties[key]=this.extendedProperties[key];
                } 
            }
            return clone; 
        } 

        protected internal void OnPropertyChanging(PropertyChangedEventArgs pcevent) { 
            if (onPropertyChangingDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID);
                onPropertyChangingDelegate(this, pcevent);
            } 
        }
 
        protected internal void RaisePropertyChanging(string name) { 
            OnPropertyChanging(new PropertyChangedEventArgs(name));
        } 

        /// 
        /// 
        public override string ToString() { 
            return RelationName;
        } 
 
        internal void ValidateMultipleNestedRelations() {
            // find all nested relations that this child table has 
            // if this relation is the only relation it has, then fine,
            // otherwise check if all relations are created from XSD, without using Key/KeyRef
            // check all keys to see autogenerated
 
            if (!this.Nested || !CheckMultipleNested) // no need for this verification
                return; 
 
            if (0 <  ChildTable.NestedParentRelations.Length) {
                DataColumn[] childCols = ChildColumns; 
                if (childCols.Length != 1 || !IsAutoGenerated(childCols[0])) {
                    throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName);
                }
 
                if (!XmlTreeGen.AutoGenerated(this)) {
                    throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName); 
                } 

                foreach (Constraint cs in ChildTable.Constraints) { 
                    if (cs is ForeignKeyConstraint) {
                        ForeignKeyConstraint fk = (ForeignKeyConstraint) cs;
                        if (!XmlTreeGen.AutoGenerated(fk, true)) {
                            throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName); 
                        }
                    } 
                    else { 
                        UniqueConstraint unique = (UniqueConstraint) cs;
                        if (!XmlTreeGen.AutoGenerated(unique)) { 
                            throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName);
                        }
                    }
                } 

            } 
        } 

        private bool IsAutoGenerated(DataColumn col) { 
            if (col.ColumnMapping != MappingType.Hidden)
                return false;
            if (col.DataType != typeof(int))
                return false; 
            string generatedname = col.Table.TableName+"_Id";
 
            if ((col.ColumnName == generatedname) || (col.ColumnName == generatedname+"_0")) 
                return true;
 
            generatedname = this.ParentColumnsReference[0].Table.TableName+"_Id";
            if ((col.ColumnName == generatedname) || (col.ColumnName == generatedname+"_0"))
                return true;
 
            return false;
        } 
 
        internal int ObjectID {
            get { 
                return _objectID;
            }
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
// [....] 
//----------------------------------------------------------------------------- 

/***************************************************************************************************** 
Rules for Multiple Nested Parent, enforce following constraints

1) At all times, only 1(ONE) FK can be NON-Null in a row.
2) NULL FK values are not associated with PARENT(x), even if if PK is NULL in Parent 
3) Enforce  when
        a) Any FK value is changed 
        b) A relation created that result in Multiple Nested Child 

WriteXml 

1) WriteXml will throw if  is violated
2) if NON-Null FK has parentRow (boolean check) print as Nested, else it will get written as normal row
 
additional notes:
We decided to enforce the rule 1 just if Xml being persisted 
******************************************************************************************************/ 

namespace System.Data { 
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization; 
    using System.Data.Common;
    using System.Collections.Generic; 
 
    /// 
    ///     
    ///       Represents a parent/child relationship between two tables.
    ///    
    /// 
    [ 
    DefaultProperty("RelationName"),
    Editor("Microsoft.VSDesigner.Data.Design.DataRelationEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing), 
    TypeConverter(typeof(RelationshipConverter)), 
    ]
#if WINFSInternalOnly 
    internal
#else
    public
#endif 
    class DataRelation {
 
        // properties 
        private DataSet dataSet    = null;
        internal PropertyCollection extendedProperties = null; 
        internal string relationName   = "";

        // events
        private PropertyChangedEventHandler onPropertyChangingDelegate = null; 

        // state 
        private DataKey childKey; 
        private DataKey parentKey;
        private UniqueConstraint parentKeyConstraint = null; 
        private ForeignKeyConstraint childKeyConstraint = null;

        // Design time serialization
        internal string[] parentColumnNames = null; 
        internal string[] childColumnNames = null;
        internal string parentTableName = null; 
        internal string childTableName = null; 
        internal string parentTableNamespace= null;
        internal string childTableNamespace = null; 

        /// 
        /// this stores whether the  child element appears beneath the parent in the XML persised files.
        ///  
        internal bool nested = false;
 
        ///  
        /// this stores whether the the relationship should make sure that KeyConstraints and ForeignKeyConstraints
        /// exist when added to the ConstraintsCollections of the table. 
        /// 
        internal bool createConstraints;

        private bool _checkMultipleNested = true; 

        private static int _objectTypeCount; // Bid counter 
        private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); 

        ///  
        ///    
        ///       Initializes a new instance of the  class using the specified name,
        ///       parent, and child columns.
        ///     
        /// 
        public DataRelation(string relationName, DataColumn parentColumn, DataColumn childColumn) 
        : this(relationName, parentColumn, childColumn, true) { 
        }
 
        /// 
        ///    
        ///       Initializes a new instance of the  class using the specified name, parent, and child columns, and
        ///       value to create constraints. 
        ///    
        ///  
        public DataRelation(string relationName, DataColumn parentColumn, DataColumn childColumn, bool createConstraints) { 
            Bid.Trace(" %d#, relationName='%ls', parentColumn=%d, childColumn=%d, createConstraints=%d{bool}\n",
                            ObjectID, relationName, (parentColumn != null) ? parentColumn.ObjectID : 0, (childColumn != null) ? childColumn.ObjectID : 0, 
                            createConstraints);

            DataColumn[] parentColumns = new DataColumn[1];
            parentColumns[0] = parentColumn; 
            DataColumn[] childColumns = new DataColumn[1];
            childColumns[0] = childColumn; 
            Create(relationName, parentColumns, childColumns, createConstraints); 
        }
 
        /// 
        ///    
        ///       Initializes a new instance of the  class using the specified name
        ///       and matched arrays of parent and child columns. 
        ///    
        ///  
        public DataRelation(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns) 
        : this(relationName, parentColumns, childColumns, true) {
        } 

        /// 
        ///    
        ///       Initializes a new instance of the  class using the specified name, matched arrays of parent 
        ///       and child columns, and value to create constraints.
        ///     
        ///  
        public DataRelation(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints) {
            Create(relationName, parentColumns, childColumns, createConstraints); 
        }

        // Design time constructor
        ///  
        ///    [To be supplied.]
        ///  
        [Browsable(false)] 
        public DataRelation(string relationName, string parentTableName, string childTableName, string[] parentColumnNames, string[] childColumnNames, bool nested) {
            this.relationName = relationName; 
            this.parentColumnNames = parentColumnNames;
            this.childColumnNames = childColumnNames;
            this.parentTableName = parentTableName;
            this.childTableName = childTableName; 
            this.nested = nested;
            // DataRelation(relationName, parentTableName, null, childTableName, null, parentColumnNames, childColumnNames, nested) 
        } 

        [Browsable(false)] 
        // Design time constructor
        public DataRelation(string relationName, string parentTableName, string parentTableNamespace, string childTableName, string childTableNamespace, string[] parentColumnNames, string[] childColumnNames, bool nested) {
            this.relationName = relationName;
            this.parentColumnNames = parentColumnNames; 
            this.childColumnNames = childColumnNames;
            this.parentTableName = parentTableName; 
            this.childTableName = childTableName; 
            this.parentTableNamespace = parentTableNamespace;
            this.childTableNamespace = childTableNamespace; 
            this.nested = nested;
        }

        ///  
        ///    
        ///       Gets the child columns of this relation. 
        ///     
        /// 
        [ 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.DataRelationChildColumnsDescr)
        ]
        public virtual DataColumn[] ChildColumns { 
            get {
                CheckStateForProperty(); 
                return childKey.ToArray(); 
            }
        } 

        internal DataColumn[] ChildColumnsReference {
            get {
                CheckStateForProperty(); 
                return childKey.ColumnsReference;
            } 
        } 

        ///  
        /// The internal Key object for the child table.
        /// 
        internal DataKey ChildKey {
            get { 
                CheckStateForProperty();
                return childKey; 
            } 
        }
 
        /// 
        ///    
        ///       Gets the child table of this relation.
        ///     
        /// 
        public virtual DataTable ChildTable { 
            get { 
                CheckStateForProperty();
                return childKey.Table; 
            }
        }

        ///  
        ///    
        ///       Gets the  to which the relations' collection belongs to. 
        ///     
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)] 
        public virtual DataSet DataSet {
            get {
                CheckStateForProperty();
                return dataSet; 
            }
        } 
 
        internal string[] ParentColumnNames {
            get { 
                return parentKey.GetColumnNames();
            }
        }
 
        internal string[] ChildColumnNames {
            get { 
                return childKey.GetColumnNames(); 
            }
        } 

        private static bool IsKeyNull(object[] values) {
            for (int i = 0; i < values.Length; i++) {
                if (!DataStorage.IsObjectNull(values[i])) 
                    return false;
            } 
 
            return true;
        } 

        /// 
        /// Gets the child rows for the parent row across the relation using the version given
        ///  
        internal static DataRow[] GetChildRows(DataKey parentKey, DataKey childKey, DataRow parentRow, DataRowVersion version) {
            object[] values = parentRow.GetKeyValues(parentKey, version); 
            if (IsKeyNull(values)) { 
                return childKey.Table.NewRowArray(0);
            } 

            Index index = childKey.GetSortIndex((version == DataRowVersion.Original) ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows);
            return index.GetRows(values);
        } 

        ///  
        /// Gets the parent rows for the given child row across the relation using the version given 
        /// 
        internal static DataRow[] GetParentRows(DataKey parentKey, DataKey childKey, DataRow childRow, DataRowVersion version) { 
            object[] values = childRow.GetKeyValues(childKey, version);
            if (IsKeyNull(values)) {
                return parentKey.Table.NewRowArray(0);
            } 

            Index index = parentKey.GetSortIndex((version == DataRowVersion.Original) ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows); 
            return index.GetRows(values); 
        }
 
        internal static DataRow GetParentRow(DataKey parentKey, DataKey childKey, DataRow childRow, DataRowVersion version) {
            if (!childRow.HasVersion((version == DataRowVersion.Original) ? DataRowVersion.Original : DataRowVersion.Current))
                if (childRow.tempRecord == -1)
                    return null; 

            object[] values = childRow.GetKeyValues(childKey, version); 
            if (IsKeyNull(values)) { 
                return null;
            } 

            Index index = parentKey.GetSortIndex((version == DataRowVersion.Original) ? DataViewRowState.OriginalRows : DataViewRowState.CurrentRows);
            Range range = index.FindRecords(values);
            if (range.IsNull) { 
                return null;
            } 
 
            if (range.Count > 1) {
                throw ExceptionBuilder.MultipleParents(); 
            }
            return parentKey.Table.recordManager[index.GetRecord(range.Min)];
        }
 

        ///  
        /// Internally sets the DataSet pointer. 
        /// 
        internal void SetDataSet(DataSet dataSet) { 
            if (this.dataSet != dataSet) {
                this.dataSet = dataSet;
            }
        } 

        internal void SetParentRowRecords(DataRow childRow, DataRow parentRow) { 
            object[] parentKeyValues = parentRow.GetKeyValues(ParentKey); 
            if (childRow.tempRecord != -1) {
                ChildTable.recordManager.SetKeyValues(childRow.tempRecord, ChildKey, parentKeyValues); 
            }
            if (childRow.newRecord != -1) {
                ChildTable.recordManager.SetKeyValues(childRow.newRecord, ChildKey, parentKeyValues);
            } 
            if (childRow.oldRecord != -1) {
                ChildTable.recordManager.SetKeyValues(childRow.oldRecord, ChildKey, parentKeyValues); 
            } 
        }
 
        /// 
        ///    
        ///       Gets the parent columns of this relation.
        ///     
        /// 
        [ 
        ResCategoryAttribute(Res.DataCategory_Data), 
        ResDescriptionAttribute(Res.DataRelationParentColumnsDescr)
        ] 
        public virtual DataColumn[] ParentColumns {
            get {
                CheckStateForProperty();
                return parentKey.ToArray(); 
            }
        } 
 
        internal DataColumn[] ParentColumnsReference {
            get { 
                return parentKey.ColumnsReference;
            }
        }
 
        /// 
        /// The internal constraint object for the parent table. 
        ///  
        internal DataKey ParentKey {
            get { 
                CheckStateForProperty();
                return parentKey;
            }
        } 

        ///  
        ///     
        ///       Gets the parent table of this relation.
        ///     
        /// 
        public virtual DataTable ParentTable {
            get {
                CheckStateForProperty(); 
                return parentKey.Table;
            } 
        } 

        ///  
        ///    
        ///       Gets or sets
        ///       the name used to look up this relation in the parent
        ///       data set's . 
        ///    
        ///  
        [ 
        ResCategoryAttribute(Res.DataCategory_Data),
        DefaultValue(""), 
        ResDescriptionAttribute(Res.DataRelationRelationNameDescr)
        ]
        public virtual string RelationName {
            get { 
                CheckStateForProperty();
                return relationName; 
            } 
            set {
                IntPtr hscp; 
                Bid.ScopeEnter(out hscp, " %d#, '%ls'\n", ObjectID, value);
                try {
                    if (value == null)
                        value = ""; 

                    CultureInfo locale = (dataSet != null ? dataSet.Locale : CultureInfo.CurrentCulture); 
                    if (String.Compare(relationName, value, true, locale) != 0) { 
                        if (dataSet != null) {
                            if (value.Length == 0) 
                                throw ExceptionBuilder.NoRelationName();
                            dataSet.Relations.RegisterName(value);
                            if (relationName.Length != 0)
                                dataSet.Relations.UnregisterName(relationName); 
                        }
                        this.relationName = value; 
                        ((DataRelationCollection.DataTableRelationCollection)(ParentTable.ChildRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this)); 
                        ((DataRelationCollection.DataTableRelationCollection)(ChildTable.ParentRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this));
                    } 
                    else if (String.Compare(relationName, value, false, locale) != 0) {
                        relationName = value;
                        ((DataRelationCollection.DataTableRelationCollection)(ParentTable.ChildRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this));
                        ((DataRelationCollection.DataTableRelationCollection)(ChildTable.ParentRelations)).OnRelationPropertyChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this)); 
                    }
                } 
                finally{ 
                    Bid.ScopeLeave(ref hscp);
                } 
            }
        }
        internal void CheckNamespaceValidityForNestedRelations(string ns) {
            foreach(DataRelation rel in ChildTable.ParentRelations) { 
                if (rel == this || rel.Nested) {
                    if (rel.ParentTable.Namespace != ns) { 
                        throw ExceptionBuilder.InValidNestedRelation(ChildTable.TableName); 
                    }
                } 
            }
        }

        internal void CheckNestedRelations() { 
            Bid.Trace(" %d#\n", ObjectID);
 
            Debug.Assert(DataSet == null || ! nested, "this relation supposed to be not in dataset or not nested"); 
            // 1. There is no other relation (R) that has this.ChildTable as R.ChildTable
            //  This is not valid for Whidbey anymore so the code has been removed 

            // 2. There is no loop in nested relations
#if DEBUG
            int numTables = ParentTable.DataSet.Tables.Count; 
#endif
            DataTable dt = ParentTable; 
 
            if (ChildTable == ParentTable){
                if (String.Compare(ChildTable.TableName, ChildTable.DataSet.DataSetName, true, ChildTable.DataSet.Locale) == 0) 
                   throw ExceptionBuilder.SelfnestedDatasetConflictingName(ChildTable.TableName);
                return; //allow self join tables.
            }
 
            List list = new List();
            list.Add(ChildTable); 
 
            // We have already checked for nested relaion UP
            for(int i = 0; i < list.Count; ++i) { 
                DataRelation[] relations = list[i].NestedParentRelations;
                foreach(DataRelation rel in relations) {
                    if (rel.ParentTable == ChildTable && rel.ChildTable != ChildTable) {
                        throw ExceptionBuilder.LoopInNestedRelations(ChildTable.TableName); 
                    }
                    if (!list.Contains (rel.ParentTable)) { // check for self nested 
                        list.Add(rel.ParentTable); 
                    }
                } 
            }
        }
        /********************
          The Namespace of a table nested inside multiple parents can be 
          1. Explicitly specified
          2. Inherited from Parent Table 
          3. Empty (Form = unqualified case) 
          However, Schema does not allow (3) to be a global element and multiple nested child has to be a global element.
          Therefore we'll reduce case (3) to (2) if all parents have same namespace else throw. 
         ********************/
        /// 
        ///    
        ///       Gets or sets a value indicating whether relations are nested. 
        ///    
        ///  
        [ 
        ResCategoryAttribute(Res.DataCategory_Data),
        DefaultValue(false), 
        ResDescriptionAttribute(Res.DataRelationNested)
        ]
        public virtual bool Nested {
            get { 
                CheckStateForProperty();
                return nested; 
            } 
            set {
                IntPtr hscp; 
                Bid.ScopeEnter(out hscp, " %d#, %d{bool}\n", ObjectID, value);
                try {
                    if (nested != value) {
                        if (dataSet != null) { 
                            if (value) {
                                if (ChildTable.IsNamespaceInherited()) { // if not added to collection, don't do this check 
                                    CheckNamespaceValidityForNestedRelations(ParentTable.Namespace); 
                                }
                                Debug.Assert(ChildTable != null, "On a DataSet, but not on Table. Bad state"); 
                                ForeignKeyConstraint constraint = ChildTable.Constraints.FindForeignKeyConstraint(ChildKey.ColumnsReference, ParentKey.ColumnsReference);
                                if (constraint != null) {
                                    constraint.CheckConstraint();
                                } 
                                ValidateMultipleNestedRelations();
                            } 
                        } 
                        if (!value && (parentKey.ColumnsReference[0].ColumnMapping == MappingType.Hidden))
                            throw ExceptionBuilder.RelationNestedReadOnly(); 

                        if (value) {
                          this.ParentTable.Columns.RegisterColumnName(this.ChildTable.TableName, (DataColumn)null, this.ChildTable);
                        } else { 
                          this.ParentTable.Columns.UnregisterName(this.ChildTable.TableName);
                        } 
                        RaisePropertyChanging("Nested"); 

                        if(value) { 
                            CheckNestedRelations();
                            if (this.DataSet != null)
                                if (ParentTable == ChildTable) {
                                    foreach(DataRow row in ChildTable.Rows) 
                                        row.CheckForLoops(this);
 
                                    if (ChildTable.DataSet != null && ( String.Compare(ChildTable.TableName, ChildTable.DataSet.DataSetName, true, ChildTable.DataSet.Locale) == 0) ) 
                                        throw ExceptionBuilder.DatasetConflictingName(dataSet.DataSetName);
                                    ChildTable.fNestedInDataset = false; 
                                }
                                else {
                                        foreach(DataRow row in ChildTable.Rows)
                                            row.GetParentRow(this); 
                                }
 
                            this.ParentTable.ElementColumnCount++; 
                        }
                        else { 
                            this.ParentTable.ElementColumnCount--;
                        }

                        this.nested = value; 
                        ChildTable.CacheNestedParent();
                        if (value) { 
                            if (ADP.IsEmpty(ChildTable.Namespace) && ((ChildTable.NestedParentsCount > 1) || 
                                ((ChildTable.NestedParentsCount > 0) && ! (ChildTable.DataSet.Relations.Contains(this.RelationName))))) {
                                string parentNs = null; 
                                foreach(DataRelation rel in ChildTable.ParentRelations) {
                                    if (rel.Nested) {
                                        if (null == parentNs) {
                                            parentNs = rel.ParentTable.Namespace; 
                                        }
                                        else { 
                                            if (String.Compare(parentNs, rel.ParentTable.Namespace, StringComparison.Ordinal) != 0) { 
                                                this.nested = false;
                                                throw ExceptionBuilder.InvalidParentNamespaceinNestedRelation(ChildTable.TableName); 
                                            }
                                        }
                                    }
                                } 
                                // if not already in memory , form == unqualified
                                if (CheckMultipleNested && ChildTable.tableNamespace != null && ChildTable.tableNamespace.Length == 0) { 
                                    throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName); 
                                }
                                ChildTable.tableNamespace = null; // if we dont throw, then let it inherit the Namespace 
                            }
                        }
                    }
                } 
                finally{
                    Bid.ScopeLeave(ref hscp); 
                } 
            }
        } 

        /// 
        ///    
        ///       Gets the constraint which ensures values in a column are unique. 
        ///    
        ///  
        public virtual UniqueConstraint ParentKeyConstraint { 
            get {
                CheckStateForProperty(); 
                return parentKeyConstraint;
            }
        }
 
        internal void SetParentKeyConstraint(UniqueConstraint value) {
            Debug.Assert(parentKeyConstraint == null || value == null, "ParentKeyConstraint should not have been set already."); 
            parentKeyConstraint = value; 
        }
 

        /// 
        ///    
        ///       Gets the  for the relation. 
        ///    
        ///  
        public virtual ForeignKeyConstraint ChildKeyConstraint { 
            get {
                CheckStateForProperty(); 
                return childKeyConstraint;
            }
        }
 
        /// 
        ///    Gets the collection of custom user information. 
        ///  
        [
        ResCategoryAttribute(Res.DataCategory_Data), 
        Browsable(false),
        ResDescriptionAttribute(Res.ExtendedPropertiesDescr)
        ]
        public PropertyCollection ExtendedProperties { 
            get {
                if (extendedProperties == null) { 
                    extendedProperties = new PropertyCollection(); 
                }
                return extendedProperties; 
            }
        }

        internal bool CheckMultipleNested { 
            get {
                return _checkMultipleNested; 
            } 
            set {
                _checkMultipleNested = value; 
            }
        }

        internal void SetChildKeyConstraint(ForeignKeyConstraint value) { 
            Debug.Assert(childKeyConstraint == null || value == null, "ChildKeyConstraint should not have been set already.");
            childKeyConstraint = value; 
        } 

        internal event PropertyChangedEventHandler PropertyChanging { 
            add {
                onPropertyChangingDelegate += value;
            }
            remove { 
                onPropertyChangingDelegate -= value;
            } 
        } 
        // If we're not in a dataSet relations collection, we need to verify on every property get that we're
        // still a good relation object. 
        internal void CheckState() {
            if (dataSet == null) {
                parentKey.CheckState();
                childKey.CheckState(); 

                if (parentKey.Table.DataSet != childKey.Table.DataSet) { 
                    throw ExceptionBuilder.RelationDataSetMismatch(); 
                }
 
                if (childKey.ColumnsEqual(parentKey)) {
                    throw ExceptionBuilder.KeyColumnsIdentical();
                }
 
                for (int i = 0; i < parentKey.ColumnsReference.Length; i++) {
                    if ((parentKey.ColumnsReference[i].DataType != childKey.ColumnsReference[i].DataType) || 
                        ((parentKey.ColumnsReference[i].DataType ==  typeof(DateTime)) && 
                        (parentKey.ColumnsReference[i].DateTimeMode != childKey.ColumnsReference[i].DateTimeMode) &&
                        ((parentKey.ColumnsReference[i].DateTimeMode & childKey.ColumnsReference[i].DateTimeMode) != DataSetDateTime.Unspecified))) 
                        // alow unspecified and unspecifiedlocal
                        throw ExceptionBuilder.ColumnsTypeMismatch();
                }
            } 
        }
 
        ///  
        ///    Checks to ensure the DataRelation is a valid object, even if it doesn't
        ///       belong to a . 
        /// 
        protected void CheckStateForProperty() {
            try {
                CheckState(); 
            }
            catch (Exception e) { 
                // 
                if (ADP.IsCatchableExceptionType(e)) {
                    throw ExceptionBuilder.BadObjectPropertyAccess(e.Message); 
                }
                throw;
            }
        } 

        private void Create(string relationName, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints) { 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, relationName='%ls', createConstraints=%d{bool}\n",
                               ObjectID, relationName, createConstraints); 
            try {
                this.parentKey = new DataKey(parentColumns, true);
                this.childKey = new DataKey(childColumns, true);
 
                if (parentColumns.Length != childColumns.Length)
                    throw ExceptionBuilder.KeyLengthMismatch(); 
 
                for(int i = 0; i < parentColumns.Length; i++){
                    if ((parentColumns[i].Table.DataSet == null) || (childColumns[i].Table.DataSet == null)) 
                        throw ExceptionBuilder.ParentOrChildColumnsDoNotHaveDataSet();
                }

                CheckState(); 

                this.relationName = (relationName == null ? "" : relationName); 
                this.createConstraints = createConstraints; 
            }
            finally{ 
                Bid.ScopeLeave(ref hscp);
            }
        }
 

        internal DataRelation Clone(DataSet destination) { 
            Bid.Trace(" %d#, destination=%d\n", ObjectID, (destination != null) ? destination.ObjectID : 0); 

            DataTable parent = destination.Tables[ParentTable.TableName, ParentTable.Namespace]; 
            DataTable child = destination.Tables[ChildTable.TableName, ChildTable.Namespace];
            int keyLength = parentKey.ColumnsReference.Length;

            DataColumn[] parentColumns = new DataColumn[keyLength]; 
            DataColumn[] childColumns = new DataColumn[keyLength];
 
            for (int i = 0; i < keyLength; i++) { 
                parentColumns[i] = parent.Columns[ParentKey.ColumnsReference[i].ColumnName];
                childColumns[i] = child.Columns[ChildKey.ColumnsReference[i].ColumnName]; 
            }

            DataRelation clone = new DataRelation(relationName, parentColumns, childColumns, false);
 
            clone.CheckMultipleNested = false; // disable the check  in clone as it is already created
            clone.Nested = this.Nested; 
            clone.CheckMultipleNested = true; // enable the check 

            // ...Extended Properties 
            if (this.extendedProperties != null) {
                foreach(Object key in this.extendedProperties.Keys) {
                    clone.ExtendedProperties[key]=this.extendedProperties[key];
                } 
            }
            return clone; 
        } 

        protected internal void OnPropertyChanging(PropertyChangedEventArgs pcevent) { 
            if (onPropertyChangingDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID);
                onPropertyChangingDelegate(this, pcevent);
            } 
        }
 
        protected internal void RaisePropertyChanging(string name) { 
            OnPropertyChanging(new PropertyChangedEventArgs(name));
        } 

        /// 
        /// 
        public override string ToString() { 
            return RelationName;
        } 
 
        internal void ValidateMultipleNestedRelations() {
            // find all nested relations that this child table has 
            // if this relation is the only relation it has, then fine,
            // otherwise check if all relations are created from XSD, without using Key/KeyRef
            // check all keys to see autogenerated
 
            if (!this.Nested || !CheckMultipleNested) // no need for this verification
                return; 
 
            if (0 <  ChildTable.NestedParentRelations.Length) {
                DataColumn[] childCols = ChildColumns; 
                if (childCols.Length != 1 || !IsAutoGenerated(childCols[0])) {
                    throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName);
                }
 
                if (!XmlTreeGen.AutoGenerated(this)) {
                    throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName); 
                } 

                foreach (Constraint cs in ChildTable.Constraints) { 
                    if (cs is ForeignKeyConstraint) {
                        ForeignKeyConstraint fk = (ForeignKeyConstraint) cs;
                        if (!XmlTreeGen.AutoGenerated(fk, true)) {
                            throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName); 
                        }
                    } 
                    else { 
                        UniqueConstraint unique = (UniqueConstraint) cs;
                        if (!XmlTreeGen.AutoGenerated(unique)) { 
                            throw ExceptionBuilder.TableCantBeNestedInTwoTables(ChildTable.TableName);
                        }
                    }
                } 

            } 
        } 

        private bool IsAutoGenerated(DataColumn col) { 
            if (col.ColumnMapping != MappingType.Hidden)
                return false;
            if (col.DataType != typeof(int))
                return false; 
            string generatedname = col.Table.TableName+"_Id";
 
            if ((col.ColumnName == generatedname) || (col.ColumnName == generatedname+"_0")) 
                return true;
 
            generatedname = this.ParentColumnsReference[0].Table.TableName+"_Id";
            if ((col.ColumnName == generatedname) || (col.ColumnName == generatedname+"_0"))
                return true;
 
            return false;
        } 
 
        internal int ObjectID {
            get { 
                return _objectID;
            }
        }
    } 
}

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