ConstraintCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / ConstraintCollection.cs / 1305376 / ConstraintCollection.cs

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

namespace System.Data { 
    using System;
    using System.Diagnostics;
    using System.Collections;
    using System.ComponentModel; 

    ///  
    /// Represents a collection of constraints for a  
    /// .
    ///  
    [
    DefaultEvent("CollectionChanged"),
    Editor("Microsoft.VSDesigner.Data.Design.ConstraintsCollectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
    ] 
    public sealed class ConstraintCollection : InternalDataCollectionBase { // WebData 111752
 
        private readonly DataTable table; 
        // private Constraint[] constraints = new Constraint[2];
        private readonly ArrayList list = new ArrayList(); 
        private int defaultNameIndex = 1;

        private CollectionChangeEventHandler onCollectionChanged;
        private Constraint[] delayLoadingConstraints; 
        private bool fLoadForeignKeyConstraintsOnly = false;
 
        ///  
        /// ConstraintCollection constructor.  Used only by DataTable.
        ///  
        internal ConstraintCollection(DataTable table) {
            this.table = table;
        }
 
        /// 
        ///    Gets the list of objects contained by the collection. 
        ///  
        protected override ArrayList List {
            get { 
                return list;
            }
        }
 
        /// 
        /// Gets the  
        /// from the collection at the specified index. 
        /// 
        public Constraint this[int index] { 
            get {
                if (index >= 0 && index < List.Count) {
                    return(Constraint) List[index];
                } 
                throw ExceptionBuilder.ConstraintOutOfRange(index);
            } 
        } 

        ///  
        /// The DataTable with which this ConstraintCollection is associated
        /// 
        internal DataTable Table {
            get { 
                return table;
            } 
        } 

        ///  
        /// Gets the  from the collection with the specified name.
        /// 
        public Constraint this[string name] {
            get { 
                int index = InternalIndexOf(name);
                if (index == -2) { 
                    throw ExceptionBuilder.CaseInsensitiveNameConflict(name); 
                }
                return (index < 0) ? null : (Constraint)List[index]; 
            }
        }

        ///  
        ///    
        ///       Adds the constraint to the collection. 
        ///  
        public void Add(Constraint constraint) {
            Add(constraint, true); 
        }

//       To add foreign key constraint without adding any unique constraint for internal use. Main purpose : Binary Remoting
        internal void Add(Constraint constraint, bool addUniqueWhenAddingForeign) { 

            if (constraint == null) 
                throw ExceptionBuilder.ArgumentNull("constraint"); 

            // It is an error if we find an equivalent constraint already in collection 
            if (FindConstraint(constraint) != null) {
                throw ExceptionBuilder.DuplicateConstraint(FindConstraint(constraint).ConstraintName);
            }
 
            if (1 < table.NestedParentRelations.Length) {
                if (!AutoGenerated(constraint)) { 
                    throw ExceptionBuilder.CantAddConstraintToMultipleNestedTable(table.TableName); 
                }
            } 

            if (constraint is UniqueConstraint) {
                if (((UniqueConstraint)constraint).bPrimaryKey) {
                    if (Table.primaryKey != null) { 
                        throw ExceptionBuilder.AddPrimaryKeyConstraint();
                    } 
                } 
                AddUniqueConstraint((UniqueConstraint)constraint);
            } 
            else if (constraint is ForeignKeyConstraint) {
                ForeignKeyConstraint fk = (ForeignKeyConstraint)constraint;
                if (addUniqueWhenAddingForeign) {
                    UniqueConstraint key = fk.RelatedTable.Constraints.FindKeyConstraint(fk.RelatedColumnsReference); 
                    if (key == null) {
                        if (constraint.ConstraintName.Length == 0) 
                            constraint.ConstraintName = AssignName(); 
                        else
                            RegisterName(constraint.ConstraintName); 

                        key = new UniqueConstraint(fk.RelatedColumnsReference);
                        fk.RelatedTable.Constraints.Add(key);
                    } 
                }
                AddForeignKeyConstraint((ForeignKeyConstraint)constraint); 
            } 
            BaseAdd(constraint);
            ArrayAdd(constraint); 
            OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, constraint));

            if (constraint is UniqueConstraint) {
                if (((UniqueConstraint)constraint).bPrimaryKey) { 
                    Table.PrimaryKey = ((UniqueConstraint)constraint).ColumnsReference;
                } 
            } 
        }
 
        /// 
        /// Constructs a new  using the
        ///    specified array of 
        ///    objects and adds it to the collection. 
        /// 
        public Constraint Add(string name, DataColumn[] columns, bool primaryKey) { 
            UniqueConstraint constraint = new UniqueConstraint(name, columns); 
            Add(constraint);
            if (primaryKey) 
                Table.PrimaryKey = columns;
            return constraint;
        }
 
        /// 
        /// Constructs a new  using the 
        ///    specified  and adds it to the collection. 
        /// 
        public Constraint Add(string name, DataColumn column, bool primaryKey) { 
            UniqueConstraint constraint = new UniqueConstraint(name, column);
            Add(constraint);
            if (primaryKey)
                Table.PrimaryKey = constraint.ColumnsReference; 
            return constraint;
        } 
 
        /// 
        ///     
        ///       Constructs a new 
        ///       with the
        ///       specified parent and child
        ///       columns and adds the constraint to the collection. 
        /// 
        public Constraint Add(string name, DataColumn primaryKeyColumn, DataColumn foreignKeyColumn) { 
            ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumn, foreignKeyColumn); 
            Add(constraint);
            return constraint; 
        }

        /// 
        /// Constructs a new  with the specified parent columns and 
        ///    child columns and adds the constraint to the collection.
        ///  
        public  Constraint Add(string name, DataColumn[] primaryKeyColumns, DataColumn[] foreignKeyColumns) { 
            ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumns, foreignKeyColumns);
            Add(constraint); 
            return constraint;
        }

        public void AddRange(Constraint[] constraints ) { 
            if (table.fInitInProgress) {
                delayLoadingConstraints = constraints; 
                fLoadForeignKeyConstraintsOnly = false; 
                return;
            } 

            if (constraints != null) {
                foreach(Constraint constr in constraints) {
                    if (constr != null) { 
                        Add(constr);
                    } 
                } 
            }
        } 


        private void AddUniqueConstraint(UniqueConstraint constraint) {
            DataColumn[] columns = constraint.ColumnsReference; 

            for (int i = 0; i < columns.Length; i++) { 
                if (columns[i].Table != this.table) { 
                    throw ExceptionBuilder.ConstraintForeignTable();
                } 
            }
            constraint.ConstraintIndexInitialize();

            if (!constraint.CanEnableConstraint()) { 
                constraint.ConstraintIndexClear();
                throw ExceptionBuilder.UniqueConstraintViolation(); 
            } 
        }
 
        private void AddForeignKeyConstraint(ForeignKeyConstraint constraint) {
            if (!constraint.CanEnableConstraint()) {
                throw ExceptionBuilder.ConstraintParentValues();
            } 
            constraint.CheckCanAddToCollection(this);
        } 
 
        private bool AutoGenerated(Constraint constraint) {
            ForeignKeyConstraint fk = (constraint as ForeignKeyConstraint); 
            if (null != fk) {
                return XmlTreeGen.AutoGenerated(fk, false);
            }
            else { 
                UniqueConstraint unique = (UniqueConstraint) constraint;
                return XmlTreeGen.AutoGenerated(unique); 
            } 
        }
 
        /// 
        /// Occurs when the  is changed through additions or
        ///    removals.
        ///  
        public event CollectionChangeEventHandler CollectionChanged {
            add { 
                onCollectionChanged += value; 
            }
            remove { 
                onCollectionChanged -= value;
            }
        }
 
        /// 
        ///  Adds the constraint to the constraints array. 
        ///  
        private void ArrayAdd(Constraint constraint) {
            Debug.Assert(constraint != null, "Attempt to add null constraint to constraint array"); 
            List.Add(constraint);
        }

        private void ArrayRemove(Constraint constraint) { 
            List.Remove(constraint);
        } 
 
        /// 
        /// Creates a new default name. 
        /// 
        internal string AssignName() {
            string newName = MakeName(defaultNameIndex);
            defaultNameIndex++; 
            return newName;
        } 
 
        /// 
        /// Does verification on the constraint and it's name. 
        /// An ArgumentNullException is thrown if this constraint is null.  An ArgumentException is thrown if this constraint
        /// already belongs to this collection, belongs to another collection.
        /// A DuplicateNameException is thrown if this collection already has a constraint with the same
        /// name (case insensitive). 
        /// 
        private void BaseAdd(Constraint constraint) { 
            if (constraint == null) 
                throw ExceptionBuilder.ArgumentNull("constraint");
 
            if (constraint.ConstraintName.Length == 0)
                constraint.ConstraintName = AssignName();
            else
                RegisterName(constraint.ConstraintName); 

            constraint.InCollection = true; 
        } 

        ///  
        /// BaseGroupSwitch will intelligently remove and add tables from the collection.
        /// 
        private void BaseGroupSwitch(Constraint[] oldArray, int oldLength, Constraint[] newArray, int newLength) {
            // We're doing a smart diff of oldArray and newArray to find out what 
            // should be removed.  We'll pass through oldArray and see if it exists
            // in newArray, and if not, do remove work.  newBase is an opt. in case 
            // the arrays have similar prefixes. 
            int newBase = 0;
            for (int oldCur = 0; oldCur < oldLength; oldCur++) { 
                bool found = false;
                for (int newCur = newBase; newCur < newLength; newCur++) {
                    if (oldArray[oldCur] == newArray[newCur]) {
                        if (newBase == newCur) { 
                            newBase++;
                        } 
                        found = true; 
                        break;
                    } 
                }
                if (!found) {
                    // This means it's in oldArray and not newArray.  Remove it.
                    BaseRemove(oldArray[oldCur]); 
                    List.Remove(oldArray[oldCur]);
 
                } 
            }
 
            // Now, let's pass through news and those that don't belong, add them.
            for (int newCur = 0; newCur < newLength; newCur++) {
                if (!newArray[newCur].InCollection)
                    BaseAdd(newArray[newCur]); 
                List.Add(newArray[newCur]);
            } 
        } 

        ///  
        /// Does verification on the constraint and it's name.
        /// An ArgumentNullException is thrown if this constraint is null.  An ArgumentException is thrown
        /// if this constraint doesn't belong to this collection or if this constraint is part of a relationship.
        ///  
        private void BaseRemove(Constraint constraint) {
            if (constraint == null) { 
                throw ExceptionBuilder.ArgumentNull("constraint"); 
            }
            if (constraint.Table != table) { 
                throw ExceptionBuilder.ConstraintRemoveFailed();
            }

            UnregisterName(constraint.ConstraintName); 
            constraint.InCollection = false;
 
            if (constraint is UniqueConstraint) { 
                for (int i = 0; i < Table.ChildRelations.Count; i++) {
                    DataRelation rel = Table.ChildRelations[i]; 
                    if (rel.ParentKeyConstraint == constraint)
                        rel.SetParentKeyConstraint(null);
                }
                ((UniqueConstraint)constraint).ConstraintIndexClear(); 
            }
            else if (constraint is ForeignKeyConstraint) { 
                for (int i = 0; i < Table.ParentRelations.Count; i++) { 
                    DataRelation rel = Table.ParentRelations[i];
                    if (rel.ChildKeyConstraint == constraint) 
                        rel.SetChildKeyConstraint(null);
                }
            }
        } 

        ///  
        /// Indicates if a  can be removed. 
        /// 
        // PUBLIC because called by design-time... need to consider this. 
        public bool CanRemove(Constraint constraint) {
            return CanRemove(constraint, /*fThrowException:*/false);
        }
 
        internal bool CanRemove(Constraint constraint, bool fThrowException) {
            return constraint.CanBeRemovedFromCollection(this, fThrowException); 
        } 

        ///  
        /// Clears the collection of any 
        /// objects.
        /// 
        public void Clear() { 
            if (table != null) {
                table.PrimaryKey = null; 
 
                for (int i = 0; i < table.ParentRelations.Count; i++) {
                    table.ParentRelations[i].SetChildKeyConstraint(null); 
                }
                for (int i = 0; i < table.ChildRelations.Count; i++) {
                    table.ChildRelations[i].SetParentKeyConstraint(null);
                } 
            }
 
            if (table.fInitInProgress && delayLoadingConstraints != null) { 
                delayLoadingConstraints = null;
                fLoadForeignKeyConstraintsOnly = false; 
            }

            int oldLength = List.Count;
 
            Constraint[] constraints = new Constraint[List.Count];
            List.CopyTo(constraints, 0); 
            try { 
                // this will smartly add and remove the appropriate tables.
                BaseGroupSwitch(constraints, oldLength, null, 0); 
            }
            catch (Exception e) {
                //
                if (Common.ADP.IsCatchableOrSecurityExceptionType(e)) { 
                    // something messed up.  restore to original state.
                    BaseGroupSwitch(null, 0, constraints, oldLength); 
                    List.Clear(); 
                    for (int i = 0; i < oldLength; i++)
                        List.Add(constraints[i]); 
                }
                throw;
            }
 
            List.Clear();
            OnCollectionChanged(RefreshEventArgs); 
        } 

        ///  
        /// Indicates whether the , specified by name, exists in the collection.
        /// 
        public bool Contains(string name) {
            return (InternalIndexOf(name) >= 0); 
        }
 
        internal bool Contains(string name, bool caseSensitive) { 
            if (!caseSensitive)
                return Contains(name); 
            int index = InternalIndexOf(name);
            if (index<0)
                return false;
            return (name == ((Constraint) List[index]).ConstraintName); 
        }
 
        public void CopyTo(Constraint[] array, int index) { 
            if (array==null)
                throw ExceptionBuilder.ArgumentNull("array"); 
            if (index < 0)
                throw ExceptionBuilder.ArgumentOutOfRange("index");
            if (array.Length - index < list.Count)
                throw ExceptionBuilder.InvalidOffsetLength(); 
            for(int i = 0; i < list.Count; ++i) {
                array[index + i] = (Constraint)list[i]; 
            } 
        }
 
        /// 
        /// Returns a matching constriant object.
        /// 
        internal Constraint FindConstraint(Constraint constraint) { 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                if (((Constraint)List[i]).Equals(constraint)) 
                    return(Constraint)List[i];
            } 
            return null;
        }

        ///  
        /// Returns a matching constriant object.
        ///  
        internal UniqueConstraint FindKeyConstraint(DataColumn[] columns) { 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                UniqueConstraint constraint = (List[i] as UniqueConstraint);
                 if ((null != constraint) && CompareArrays(constraint.Key.ColumnsReference, columns)) {
                    return constraint;
                 } 
            }
            return null; 
        } 

        ///  
        /// Returns a matching constriant object.
        /// 
        internal UniqueConstraint FindKeyConstraint(DataColumn column) {
            int constraintCount = List.Count; 
            for (int i = 0; i < constraintCount; i++) {
                UniqueConstraint constraint = (List[i] as UniqueConstraint); 
                if ((null != constraint) && (constraint.Key.ColumnsReference.Length == 1) && (constraint.Key.ColumnsReference[0] == column)) 
                    return constraint;
            } 
            return null;
        }

        ///  
        /// Returns a matching constriant object.
        ///  
        internal ForeignKeyConstraint FindForeignKeyConstraint(DataColumn[] parentColumns, DataColumn[] childColumns) { 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                ForeignKeyConstraint constraint = (List[i] as ForeignKeyConstraint);
                if ((null != constraint) &&
                    CompareArrays(constraint.ParentKey.ColumnsReference, parentColumns) &&
                    CompareArrays(constraint.ChildKey.ColumnsReference, childColumns)) 
                    return constraint;
            } 
            return null; 
        }
 
        private static bool CompareArrays(DataColumn[] a1, DataColumn[] a2) {
            Debug.Assert(a1 != null && a2 != null, "Invalid Arguments");
            if (a1.Length != a2.Length)
                return false; 

            int i, j; 
            for (i=0; i
        /// Returns the index of the specified  . 
        ///  
        public int IndexOf(Constraint constraint) {
            if (null != constraint) { 
                int count = Count;
                for (int i = 0; i < count; ++i) {
                    if (constraint == (Constraint) List[i])
                        return i; 
                }
                // didnt find the constraint 
            } 
            return -1;
        } 

        /// 
        /// Returns the index of the , specified by name.
        ///  
        public int IndexOf(string constraintName) {
            int index = InternalIndexOf(constraintName); 
            return (index < 0) ? -1 : index; 
        }
 
        // Return value:
        //      >= 0: find the match
        //        -1: No match
        //        -2: At least two matches with different cases 
        internal int InternalIndexOf(string constraintName) {
            int cachedI = -1; 
            if ((null != constraintName) && (0 < constraintName.Length)) { 
                int constraintCount = List.Count;
                int result = 0; 
                for (int i = 0; i < constraintCount; i++) {
                    Constraint constraint = (Constraint) List[i];
                    result = NamesEqual(constraint.ConstraintName, constraintName, false, table.Locale);
                    if (result == 1) 
                        return i;
 
                    if (result == -1) 
                        cachedI = (cachedI == -1) ? i : -2;
                } 
            }
            return cachedI;
        }
 
        /// 
        /// Makes a default name with the given index.  e.g. Constraint1, Constraint2, ... Constrainti 
        ///  
        private string MakeName(int index) {
            if (1 == index) { 
                return "Constraint1";
            }
            return "Constraint" + index.ToString(System.Globalization.CultureInfo.InvariantCulture);
        } 

        ///  
        /// Raises the  event. 
        /// 
        private void OnCollectionChanged(CollectionChangeEventArgs ccevent) { 
            if (onCollectionChanged != null) {
                onCollectionChanged(this, ccevent);
            }
        } 

        ///  
        /// Registers this name as being used in the collection.  Will throw an ArgumentException 
        /// if the name is already being used.  Called by Add, All property, and Constraint.ConstraintName property.
        /// if the name is equivalent to the next default name to hand out, we increment our defaultNameIndex. 
        /// 
        internal void RegisterName(string name) {
            Debug.Assert (name != null);
 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                if (NamesEqual(name, ((Constraint)List[i]).ConstraintName, true, table.Locale) != 0) { 
                    throw ExceptionBuilder.DuplicateConstraintName(((Constraint)List[i]).ConstraintName);
                } 
            }
            if (NamesEqual(name, MakeName(defaultNameIndex), true, table.Locale) != 0) {
                defaultNameIndex++;
            } 
        }
 
        ///  
        ///    
        ///       Removes the specified  
        ///       from the collection.
        /// 
        public void Remove(Constraint constraint) {
            if (constraint == null) 
                throw ExceptionBuilder.ArgumentNull("constraint");
 
            // this will throw an exception if it can't be removed, otherwise indicates 
            // whether we need to remove it from the collection.
            if (CanRemove(constraint, true)) { 
                // constraint can be removed
                BaseRemove(constraint);
                ArrayRemove(constraint);
                if (constraint is UniqueConstraint && ((UniqueConstraint)constraint).IsPrimaryKey) { 
                    Table.PrimaryKey = null;
                } 
 
                OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, constraint));
            } 
        }

        /// 
        ///    Removes the constraint at the specified index from the 
        ///       collection.
        ///  
        public void RemoveAt(int index) { 
            Constraint c = this[index];
            if (c == null) 
                throw ExceptionBuilder.ConstraintOutOfRange(index);
            Remove(c);
        }
 
        /// 
        ///    Removes the constraint, specified by name, from the collection. 
        ///  
        public void Remove(string name) {
            Constraint c = this[name]; 
            if (c == null)
                throw ExceptionBuilder.ConstraintNotInTheTable(name);
            Remove(c);
        } 

        ///  
        /// Unregisters this name as no longer being used in the collection.  Called by Remove, All property, and 
        /// Constraint.ConstraintName property.  If the name is equivalent to the last proposed default namem, we walk backwards
        /// to find the next proper default name to hang out. 
        /// 
        internal void UnregisterName(string name) {
            if (NamesEqual(name, MakeName(defaultNameIndex - 1), true, table.Locale) != 0) {
                do { 
                    defaultNameIndex--;
                } while (defaultNameIndex > 1 && 
                         !Contains(MakeName(defaultNameIndex - 1))); 
            }
        } 

        internal void FinishInitConstraints() {
            if (delayLoadingConstraints == null)
                return; 

            int colCount; 
            DataColumn[] parents, childs; 
            for (int i = 0; i < delayLoadingConstraints.Length; i++) {
                if (delayLoadingConstraints[i] is UniqueConstraint) { 
                    if (fLoadForeignKeyConstraintsOnly)
                        continue;

                    UniqueConstraint constr = (UniqueConstraint) delayLoadingConstraints[i]; 
                    if (constr.columnNames == null) {
                        this.Add(constr); 
                        continue; 
                    }
                    colCount = constr.columnNames.Length; 
                    parents = new DataColumn[colCount];
                    for (int j = 0; j < colCount; j++)
                        parents[j] = table.Columns[constr.columnNames[j]];
                    if (constr.bPrimaryKey) { 
                        if (table.primaryKey != null) {
                            throw ExceptionBuilder.AddPrimaryKeyConstraint(); 
                        } 
                        else {
                            Add(constr.ConstraintName,parents,true); 
                        }
                        continue;
                    }
                    UniqueConstraint newConstraint = new UniqueConstraint(constr.constraintName, parents); 
                    if (FindConstraint(newConstraint) == null)
                        this.Add(newConstraint); 
                } 
                else {
                    ForeignKeyConstraint constr = (ForeignKeyConstraint) delayLoadingConstraints[i]; 
                    if (constr.parentColumnNames == null ||constr.childColumnNames == null) {
                        this.Add(constr);
                        continue;
                    } 

                    if (table.DataSet == null) { 
                        fLoadForeignKeyConstraintsOnly = true; 
                        continue;
                    } 

                    colCount = constr.parentColumnNames.Length;
                    parents = new DataColumn[colCount];
                    childs = new DataColumn[colCount]; 
                    for (int j = 0; j < colCount; j++) {
                        if (constr.parentTableNamespace == null) 
                            parents[j] = table.DataSet.Tables[constr.parentTableName].Columns[constr.parentColumnNames[j]]; 
                        else
                            parents[j] = table.DataSet.Tables[constr.parentTableName, constr.parentTableNamespace].Columns[constr.parentColumnNames[j]]; 
                        childs[j] =  table.Columns[constr.childColumnNames[j]];
                    }
                    ForeignKeyConstraint newConstraint = new ForeignKeyConstraint(constr.constraintName, parents, childs);
                    newConstraint.AcceptRejectRule = constr.acceptRejectRule; 
                    newConstraint.DeleteRule = constr.deleteRule;
                    newConstraint.UpdateRule = constr.updateRule; 
                    this.Add(newConstraint); 
                }
            } 

            if (!fLoadForeignKeyConstraintsOnly)
                delayLoadingConstraints = null;
        } 
    }
} 

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

namespace System.Data { 
    using System;
    using System.Diagnostics;
    using System.Collections;
    using System.ComponentModel; 

    ///  
    /// Represents a collection of constraints for a  
    /// .
    ///  
    [
    DefaultEvent("CollectionChanged"),
    Editor("Microsoft.VSDesigner.Data.Design.ConstraintsCollectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
    ] 
    public sealed class ConstraintCollection : InternalDataCollectionBase { // WebData 111752
 
        private readonly DataTable table; 
        // private Constraint[] constraints = new Constraint[2];
        private readonly ArrayList list = new ArrayList(); 
        private int defaultNameIndex = 1;

        private CollectionChangeEventHandler onCollectionChanged;
        private Constraint[] delayLoadingConstraints; 
        private bool fLoadForeignKeyConstraintsOnly = false;
 
        ///  
        /// ConstraintCollection constructor.  Used only by DataTable.
        ///  
        internal ConstraintCollection(DataTable table) {
            this.table = table;
        }
 
        /// 
        ///    Gets the list of objects contained by the collection. 
        ///  
        protected override ArrayList List {
            get { 
                return list;
            }
        }
 
        /// 
        /// Gets the  
        /// from the collection at the specified index. 
        /// 
        public Constraint this[int index] { 
            get {
                if (index >= 0 && index < List.Count) {
                    return(Constraint) List[index];
                } 
                throw ExceptionBuilder.ConstraintOutOfRange(index);
            } 
        } 

        ///  
        /// The DataTable with which this ConstraintCollection is associated
        /// 
        internal DataTable Table {
            get { 
                return table;
            } 
        } 

        ///  
        /// Gets the  from the collection with the specified name.
        /// 
        public Constraint this[string name] {
            get { 
                int index = InternalIndexOf(name);
                if (index == -2) { 
                    throw ExceptionBuilder.CaseInsensitiveNameConflict(name); 
                }
                return (index < 0) ? null : (Constraint)List[index]; 
            }
        }

        ///  
        ///    
        ///       Adds the constraint to the collection. 
        ///  
        public void Add(Constraint constraint) {
            Add(constraint, true); 
        }

//       To add foreign key constraint without adding any unique constraint for internal use. Main purpose : Binary Remoting
        internal void Add(Constraint constraint, bool addUniqueWhenAddingForeign) { 

            if (constraint == null) 
                throw ExceptionBuilder.ArgumentNull("constraint"); 

            // It is an error if we find an equivalent constraint already in collection 
            if (FindConstraint(constraint) != null) {
                throw ExceptionBuilder.DuplicateConstraint(FindConstraint(constraint).ConstraintName);
            }
 
            if (1 < table.NestedParentRelations.Length) {
                if (!AutoGenerated(constraint)) { 
                    throw ExceptionBuilder.CantAddConstraintToMultipleNestedTable(table.TableName); 
                }
            } 

            if (constraint is UniqueConstraint) {
                if (((UniqueConstraint)constraint).bPrimaryKey) {
                    if (Table.primaryKey != null) { 
                        throw ExceptionBuilder.AddPrimaryKeyConstraint();
                    } 
                } 
                AddUniqueConstraint((UniqueConstraint)constraint);
            } 
            else if (constraint is ForeignKeyConstraint) {
                ForeignKeyConstraint fk = (ForeignKeyConstraint)constraint;
                if (addUniqueWhenAddingForeign) {
                    UniqueConstraint key = fk.RelatedTable.Constraints.FindKeyConstraint(fk.RelatedColumnsReference); 
                    if (key == null) {
                        if (constraint.ConstraintName.Length == 0) 
                            constraint.ConstraintName = AssignName(); 
                        else
                            RegisterName(constraint.ConstraintName); 

                        key = new UniqueConstraint(fk.RelatedColumnsReference);
                        fk.RelatedTable.Constraints.Add(key);
                    } 
                }
                AddForeignKeyConstraint((ForeignKeyConstraint)constraint); 
            } 
            BaseAdd(constraint);
            ArrayAdd(constraint); 
            OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, constraint));

            if (constraint is UniqueConstraint) {
                if (((UniqueConstraint)constraint).bPrimaryKey) { 
                    Table.PrimaryKey = ((UniqueConstraint)constraint).ColumnsReference;
                } 
            } 
        }
 
        /// 
        /// Constructs a new  using the
        ///    specified array of 
        ///    objects and adds it to the collection. 
        /// 
        public Constraint Add(string name, DataColumn[] columns, bool primaryKey) { 
            UniqueConstraint constraint = new UniqueConstraint(name, columns); 
            Add(constraint);
            if (primaryKey) 
                Table.PrimaryKey = columns;
            return constraint;
        }
 
        /// 
        /// Constructs a new  using the 
        ///    specified  and adds it to the collection. 
        /// 
        public Constraint Add(string name, DataColumn column, bool primaryKey) { 
            UniqueConstraint constraint = new UniqueConstraint(name, column);
            Add(constraint);
            if (primaryKey)
                Table.PrimaryKey = constraint.ColumnsReference; 
            return constraint;
        } 
 
        /// 
        ///     
        ///       Constructs a new 
        ///       with the
        ///       specified parent and child
        ///       columns and adds the constraint to the collection. 
        /// 
        public Constraint Add(string name, DataColumn primaryKeyColumn, DataColumn foreignKeyColumn) { 
            ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumn, foreignKeyColumn); 
            Add(constraint);
            return constraint; 
        }

        /// 
        /// Constructs a new  with the specified parent columns and 
        ///    child columns and adds the constraint to the collection.
        ///  
        public  Constraint Add(string name, DataColumn[] primaryKeyColumns, DataColumn[] foreignKeyColumns) { 
            ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumns, foreignKeyColumns);
            Add(constraint); 
            return constraint;
        }

        public void AddRange(Constraint[] constraints ) { 
            if (table.fInitInProgress) {
                delayLoadingConstraints = constraints; 
                fLoadForeignKeyConstraintsOnly = false; 
                return;
            } 

            if (constraints != null) {
                foreach(Constraint constr in constraints) {
                    if (constr != null) { 
                        Add(constr);
                    } 
                } 
            }
        } 


        private void AddUniqueConstraint(UniqueConstraint constraint) {
            DataColumn[] columns = constraint.ColumnsReference; 

            for (int i = 0; i < columns.Length; i++) { 
                if (columns[i].Table != this.table) { 
                    throw ExceptionBuilder.ConstraintForeignTable();
                } 
            }
            constraint.ConstraintIndexInitialize();

            if (!constraint.CanEnableConstraint()) { 
                constraint.ConstraintIndexClear();
                throw ExceptionBuilder.UniqueConstraintViolation(); 
            } 
        }
 
        private void AddForeignKeyConstraint(ForeignKeyConstraint constraint) {
            if (!constraint.CanEnableConstraint()) {
                throw ExceptionBuilder.ConstraintParentValues();
            } 
            constraint.CheckCanAddToCollection(this);
        } 
 
        private bool AutoGenerated(Constraint constraint) {
            ForeignKeyConstraint fk = (constraint as ForeignKeyConstraint); 
            if (null != fk) {
                return XmlTreeGen.AutoGenerated(fk, false);
            }
            else { 
                UniqueConstraint unique = (UniqueConstraint) constraint;
                return XmlTreeGen.AutoGenerated(unique); 
            } 
        }
 
        /// 
        /// Occurs when the  is changed through additions or
        ///    removals.
        ///  
        public event CollectionChangeEventHandler CollectionChanged {
            add { 
                onCollectionChanged += value; 
            }
            remove { 
                onCollectionChanged -= value;
            }
        }
 
        /// 
        ///  Adds the constraint to the constraints array. 
        ///  
        private void ArrayAdd(Constraint constraint) {
            Debug.Assert(constraint != null, "Attempt to add null constraint to constraint array"); 
            List.Add(constraint);
        }

        private void ArrayRemove(Constraint constraint) { 
            List.Remove(constraint);
        } 
 
        /// 
        /// Creates a new default name. 
        /// 
        internal string AssignName() {
            string newName = MakeName(defaultNameIndex);
            defaultNameIndex++; 
            return newName;
        } 
 
        /// 
        /// Does verification on the constraint and it's name. 
        /// An ArgumentNullException is thrown if this constraint is null.  An ArgumentException is thrown if this constraint
        /// already belongs to this collection, belongs to another collection.
        /// A DuplicateNameException is thrown if this collection already has a constraint with the same
        /// name (case insensitive). 
        /// 
        private void BaseAdd(Constraint constraint) { 
            if (constraint == null) 
                throw ExceptionBuilder.ArgumentNull("constraint");
 
            if (constraint.ConstraintName.Length == 0)
                constraint.ConstraintName = AssignName();
            else
                RegisterName(constraint.ConstraintName); 

            constraint.InCollection = true; 
        } 

        ///  
        /// BaseGroupSwitch will intelligently remove and add tables from the collection.
        /// 
        private void BaseGroupSwitch(Constraint[] oldArray, int oldLength, Constraint[] newArray, int newLength) {
            // We're doing a smart diff of oldArray and newArray to find out what 
            // should be removed.  We'll pass through oldArray and see if it exists
            // in newArray, and if not, do remove work.  newBase is an opt. in case 
            // the arrays have similar prefixes. 
            int newBase = 0;
            for (int oldCur = 0; oldCur < oldLength; oldCur++) { 
                bool found = false;
                for (int newCur = newBase; newCur < newLength; newCur++) {
                    if (oldArray[oldCur] == newArray[newCur]) {
                        if (newBase == newCur) { 
                            newBase++;
                        } 
                        found = true; 
                        break;
                    } 
                }
                if (!found) {
                    // This means it's in oldArray and not newArray.  Remove it.
                    BaseRemove(oldArray[oldCur]); 
                    List.Remove(oldArray[oldCur]);
 
                } 
            }
 
            // Now, let's pass through news and those that don't belong, add them.
            for (int newCur = 0; newCur < newLength; newCur++) {
                if (!newArray[newCur].InCollection)
                    BaseAdd(newArray[newCur]); 
                List.Add(newArray[newCur]);
            } 
        } 

        ///  
        /// Does verification on the constraint and it's name.
        /// An ArgumentNullException is thrown if this constraint is null.  An ArgumentException is thrown
        /// if this constraint doesn't belong to this collection or if this constraint is part of a relationship.
        ///  
        private void BaseRemove(Constraint constraint) {
            if (constraint == null) { 
                throw ExceptionBuilder.ArgumentNull("constraint"); 
            }
            if (constraint.Table != table) { 
                throw ExceptionBuilder.ConstraintRemoveFailed();
            }

            UnregisterName(constraint.ConstraintName); 
            constraint.InCollection = false;
 
            if (constraint is UniqueConstraint) { 
                for (int i = 0; i < Table.ChildRelations.Count; i++) {
                    DataRelation rel = Table.ChildRelations[i]; 
                    if (rel.ParentKeyConstraint == constraint)
                        rel.SetParentKeyConstraint(null);
                }
                ((UniqueConstraint)constraint).ConstraintIndexClear(); 
            }
            else if (constraint is ForeignKeyConstraint) { 
                for (int i = 0; i < Table.ParentRelations.Count; i++) { 
                    DataRelation rel = Table.ParentRelations[i];
                    if (rel.ChildKeyConstraint == constraint) 
                        rel.SetChildKeyConstraint(null);
                }
            }
        } 

        ///  
        /// Indicates if a  can be removed. 
        /// 
        // PUBLIC because called by design-time... need to consider this. 
        public bool CanRemove(Constraint constraint) {
            return CanRemove(constraint, /*fThrowException:*/false);
        }
 
        internal bool CanRemove(Constraint constraint, bool fThrowException) {
            return constraint.CanBeRemovedFromCollection(this, fThrowException); 
        } 

        ///  
        /// Clears the collection of any 
        /// objects.
        /// 
        public void Clear() { 
            if (table != null) {
                table.PrimaryKey = null; 
 
                for (int i = 0; i < table.ParentRelations.Count; i++) {
                    table.ParentRelations[i].SetChildKeyConstraint(null); 
                }
                for (int i = 0; i < table.ChildRelations.Count; i++) {
                    table.ChildRelations[i].SetParentKeyConstraint(null);
                } 
            }
 
            if (table.fInitInProgress && delayLoadingConstraints != null) { 
                delayLoadingConstraints = null;
                fLoadForeignKeyConstraintsOnly = false; 
            }

            int oldLength = List.Count;
 
            Constraint[] constraints = new Constraint[List.Count];
            List.CopyTo(constraints, 0); 
            try { 
                // this will smartly add and remove the appropriate tables.
                BaseGroupSwitch(constraints, oldLength, null, 0); 
            }
            catch (Exception e) {
                //
                if (Common.ADP.IsCatchableOrSecurityExceptionType(e)) { 
                    // something messed up.  restore to original state.
                    BaseGroupSwitch(null, 0, constraints, oldLength); 
                    List.Clear(); 
                    for (int i = 0; i < oldLength; i++)
                        List.Add(constraints[i]); 
                }
                throw;
            }
 
            List.Clear();
            OnCollectionChanged(RefreshEventArgs); 
        } 

        ///  
        /// Indicates whether the , specified by name, exists in the collection.
        /// 
        public bool Contains(string name) {
            return (InternalIndexOf(name) >= 0); 
        }
 
        internal bool Contains(string name, bool caseSensitive) { 
            if (!caseSensitive)
                return Contains(name); 
            int index = InternalIndexOf(name);
            if (index<0)
                return false;
            return (name == ((Constraint) List[index]).ConstraintName); 
        }
 
        public void CopyTo(Constraint[] array, int index) { 
            if (array==null)
                throw ExceptionBuilder.ArgumentNull("array"); 
            if (index < 0)
                throw ExceptionBuilder.ArgumentOutOfRange("index");
            if (array.Length - index < list.Count)
                throw ExceptionBuilder.InvalidOffsetLength(); 
            for(int i = 0; i < list.Count; ++i) {
                array[index + i] = (Constraint)list[i]; 
            } 
        }
 
        /// 
        /// Returns a matching constriant object.
        /// 
        internal Constraint FindConstraint(Constraint constraint) { 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                if (((Constraint)List[i]).Equals(constraint)) 
                    return(Constraint)List[i];
            } 
            return null;
        }

        ///  
        /// Returns a matching constriant object.
        ///  
        internal UniqueConstraint FindKeyConstraint(DataColumn[] columns) { 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                UniqueConstraint constraint = (List[i] as UniqueConstraint);
                 if ((null != constraint) && CompareArrays(constraint.Key.ColumnsReference, columns)) {
                    return constraint;
                 } 
            }
            return null; 
        } 

        ///  
        /// Returns a matching constriant object.
        /// 
        internal UniqueConstraint FindKeyConstraint(DataColumn column) {
            int constraintCount = List.Count; 
            for (int i = 0; i < constraintCount; i++) {
                UniqueConstraint constraint = (List[i] as UniqueConstraint); 
                if ((null != constraint) && (constraint.Key.ColumnsReference.Length == 1) && (constraint.Key.ColumnsReference[0] == column)) 
                    return constraint;
            } 
            return null;
        }

        ///  
        /// Returns a matching constriant object.
        ///  
        internal ForeignKeyConstraint FindForeignKeyConstraint(DataColumn[] parentColumns, DataColumn[] childColumns) { 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                ForeignKeyConstraint constraint = (List[i] as ForeignKeyConstraint);
                if ((null != constraint) &&
                    CompareArrays(constraint.ParentKey.ColumnsReference, parentColumns) &&
                    CompareArrays(constraint.ChildKey.ColumnsReference, childColumns)) 
                    return constraint;
            } 
            return null; 
        }
 
        private static bool CompareArrays(DataColumn[] a1, DataColumn[] a2) {
            Debug.Assert(a1 != null && a2 != null, "Invalid Arguments");
            if (a1.Length != a2.Length)
                return false; 

            int i, j; 
            for (i=0; i
        /// Returns the index of the specified  . 
        ///  
        public int IndexOf(Constraint constraint) {
            if (null != constraint) { 
                int count = Count;
                for (int i = 0; i < count; ++i) {
                    if (constraint == (Constraint) List[i])
                        return i; 
                }
                // didnt find the constraint 
            } 
            return -1;
        } 

        /// 
        /// Returns the index of the , specified by name.
        ///  
        public int IndexOf(string constraintName) {
            int index = InternalIndexOf(constraintName); 
            return (index < 0) ? -1 : index; 
        }
 
        // Return value:
        //      >= 0: find the match
        //        -1: No match
        //        -2: At least two matches with different cases 
        internal int InternalIndexOf(string constraintName) {
            int cachedI = -1; 
            if ((null != constraintName) && (0 < constraintName.Length)) { 
                int constraintCount = List.Count;
                int result = 0; 
                for (int i = 0; i < constraintCount; i++) {
                    Constraint constraint = (Constraint) List[i];
                    result = NamesEqual(constraint.ConstraintName, constraintName, false, table.Locale);
                    if (result == 1) 
                        return i;
 
                    if (result == -1) 
                        cachedI = (cachedI == -1) ? i : -2;
                } 
            }
            return cachedI;
        }
 
        /// 
        /// Makes a default name with the given index.  e.g. Constraint1, Constraint2, ... Constrainti 
        ///  
        private string MakeName(int index) {
            if (1 == index) { 
                return "Constraint1";
            }
            return "Constraint" + index.ToString(System.Globalization.CultureInfo.InvariantCulture);
        } 

        ///  
        /// Raises the  event. 
        /// 
        private void OnCollectionChanged(CollectionChangeEventArgs ccevent) { 
            if (onCollectionChanged != null) {
                onCollectionChanged(this, ccevent);
            }
        } 

        ///  
        /// Registers this name as being used in the collection.  Will throw an ArgumentException 
        /// if the name is already being used.  Called by Add, All property, and Constraint.ConstraintName property.
        /// if the name is equivalent to the next default name to hand out, we increment our defaultNameIndex. 
        /// 
        internal void RegisterName(string name) {
            Debug.Assert (name != null);
 
            int constraintCount = List.Count;
            for (int i = 0; i < constraintCount; i++) { 
                if (NamesEqual(name, ((Constraint)List[i]).ConstraintName, true, table.Locale) != 0) { 
                    throw ExceptionBuilder.DuplicateConstraintName(((Constraint)List[i]).ConstraintName);
                } 
            }
            if (NamesEqual(name, MakeName(defaultNameIndex), true, table.Locale) != 0) {
                defaultNameIndex++;
            } 
        }
 
        ///  
        ///    
        ///       Removes the specified  
        ///       from the collection.
        /// 
        public void Remove(Constraint constraint) {
            if (constraint == null) 
                throw ExceptionBuilder.ArgumentNull("constraint");
 
            // this will throw an exception if it can't be removed, otherwise indicates 
            // whether we need to remove it from the collection.
            if (CanRemove(constraint, true)) { 
                // constraint can be removed
                BaseRemove(constraint);
                ArrayRemove(constraint);
                if (constraint is UniqueConstraint && ((UniqueConstraint)constraint).IsPrimaryKey) { 
                    Table.PrimaryKey = null;
                } 
 
                OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, constraint));
            } 
        }

        /// 
        ///    Removes the constraint at the specified index from the 
        ///       collection.
        ///  
        public void RemoveAt(int index) { 
            Constraint c = this[index];
            if (c == null) 
                throw ExceptionBuilder.ConstraintOutOfRange(index);
            Remove(c);
        }
 
        /// 
        ///    Removes the constraint, specified by name, from the collection. 
        ///  
        public void Remove(string name) {
            Constraint c = this[name]; 
            if (c == null)
                throw ExceptionBuilder.ConstraintNotInTheTable(name);
            Remove(c);
        } 

        ///  
        /// Unregisters this name as no longer being used in the collection.  Called by Remove, All property, and 
        /// Constraint.ConstraintName property.  If the name is equivalent to the last proposed default namem, we walk backwards
        /// to find the next proper default name to hang out. 
        /// 
        internal void UnregisterName(string name) {
            if (NamesEqual(name, MakeName(defaultNameIndex - 1), true, table.Locale) != 0) {
                do { 
                    defaultNameIndex--;
                } while (defaultNameIndex > 1 && 
                         !Contains(MakeName(defaultNameIndex - 1))); 
            }
        } 

        internal void FinishInitConstraints() {
            if (delayLoadingConstraints == null)
                return; 

            int colCount; 
            DataColumn[] parents, childs; 
            for (int i = 0; i < delayLoadingConstraints.Length; i++) {
                if (delayLoadingConstraints[i] is UniqueConstraint) { 
                    if (fLoadForeignKeyConstraintsOnly)
                        continue;

                    UniqueConstraint constr = (UniqueConstraint) delayLoadingConstraints[i]; 
                    if (constr.columnNames == null) {
                        this.Add(constr); 
                        continue; 
                    }
                    colCount = constr.columnNames.Length; 
                    parents = new DataColumn[colCount];
                    for (int j = 0; j < colCount; j++)
                        parents[j] = table.Columns[constr.columnNames[j]];
                    if (constr.bPrimaryKey) { 
                        if (table.primaryKey != null) {
                            throw ExceptionBuilder.AddPrimaryKeyConstraint(); 
                        } 
                        else {
                            Add(constr.ConstraintName,parents,true); 
                        }
                        continue;
                    }
                    UniqueConstraint newConstraint = new UniqueConstraint(constr.constraintName, parents); 
                    if (FindConstraint(newConstraint) == null)
                        this.Add(newConstraint); 
                } 
                else {
                    ForeignKeyConstraint constr = (ForeignKeyConstraint) delayLoadingConstraints[i]; 
                    if (constr.parentColumnNames == null ||constr.childColumnNames == null) {
                        this.Add(constr);
                        continue;
                    } 

                    if (table.DataSet == null) { 
                        fLoadForeignKeyConstraintsOnly = true; 
                        continue;
                    } 

                    colCount = constr.parentColumnNames.Length;
                    parents = new DataColumn[colCount];
                    childs = new DataColumn[colCount]; 
                    for (int j = 0; j < colCount; j++) {
                        if (constr.parentTableNamespace == null) 
                            parents[j] = table.DataSet.Tables[constr.parentTableName].Columns[constr.parentColumnNames[j]]; 
                        else
                            parents[j] = table.DataSet.Tables[constr.parentTableName, constr.parentTableNamespace].Columns[constr.parentColumnNames[j]]; 
                        childs[j] =  table.Columns[constr.childColumnNames[j]];
                    }
                    ForeignKeyConstraint newConstraint = new ForeignKeyConstraint(constr.constraintName, parents, childs);
                    newConstraint.AcceptRejectRule = constr.acceptRejectRule; 
                    newConstraint.DeleteRule = constr.deleteRule;
                    newConstraint.UpdateRule = constr.updateRule; 
                    this.Add(newConstraint); 
                }
            } 

            if (!fLoadForeignKeyConstraintsOnly)
                delayLoadingConstraints = null;
        } 
    }
} 

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