DataTableCollection.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 / DataTableCollection.cs / 1305376 / DataTableCollection.cs

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

namespace System.Data { 
    using System;
    using System.Diagnostics;
    using System.Collections;
    using System.ComponentModel; 
    using System.Globalization;
 
    ///  
    ///    
    ///       Represents the collection of tables for the . 
    ///    
    /// 
    [
    DefaultEvent("CollectionChanged"), 
    Editor("Microsoft.VSDesigner.Data.Design.TablesCollectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
    ListBindable(false), 
    ] 
    public sealed class DataTableCollection : InternalDataCollectionBase {
 
        private readonly DataSet dataSet      = null;
        // private DataTable[] tables   = new DataTable[2];
        // private int tableCount       = 0;
        private readonly ArrayList _list = new ArrayList(); 
        private int defaultNameIndex = 1;
        private DataTable[] delayedAddRangeTables = null; 
 
        private CollectionChangeEventHandler onCollectionChangedDelegate = null;
        private CollectionChangeEventHandler onCollectionChangingDelegate = null; 

        private static int _objectTypeCount; // Bid counter
        private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
 
        /// 
        /// DataTableCollection constructor.  Used only by DataSet. 
        ///  
        internal DataTableCollection(DataSet dataSet) {
            Bid.Trace(" %d#, dataSet=%d\n", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0); 
            this.dataSet = dataSet;
        }

        ///  
        ///    
        ///       Gets the tables 
        ///       in the collection as an object. 
        ///    
        ///  
        protected override ArrayList List {
            get {
                return _list;
            } 
        }
 
        internal int ObjectID { 
            get {
                return _objectID; 
            }
        }

        ///  
        ///    Gets the table specified by its index.
        ///  
        public DataTable this[int index] { 
            get {
                try { // Perf: use the readonly _list field directly and let ArrayList check the range 
                    return(DataTable) _list[index];
                }
                catch(ArgumentOutOfRangeException) {
                    throw ExceptionBuilder.TableOutOfRange(index); 
                }
            } 
        } 

        ///  
        ///    Gets the table in the collection with the given name (not case-sensitive).
        /// 
        public DataTable this[string name] {
            get { 
                int index = InternalIndexOf(name);
                if (index == -2) { 
                    throw ExceptionBuilder.CaseInsensitiveNameConflict(name); 
                }
                if (index == -3) { 
                    throw ExceptionBuilder.NamespaceNameConflict(name);
                }
                return (index < 0) ? null : (DataTable)_list[index];
            } 
        }
 
        public DataTable this[string name, string tableNamespace] { 
            get {
                if (tableNamespace == null) 
                    throw ExceptionBuilder.ArgumentNull("tableNamespace");
                int index = InternalIndexOf(name, tableNamespace);
                if (index == -2) {
                    throw ExceptionBuilder.CaseInsensitiveNameConflict(name); 
                }
                return (index < 0) ? null : (DataTable)_list[index]; 
            } 
        }
 
        // Case-sensitive search in Schema, data and diffgram loading
        internal DataTable GetTable(string name, string ns)
        {
            for (int i = 0; i < _list.Count; i++) { 
                DataTable   table = (DataTable) _list[i];
                if (table.TableName == name && table.Namespace == ns) 
                    return table; 
            }
            return null; 
        }

        // Case-sensitive smart search: it will look for a table using the ns only if required to
        // resolve a conflict 
        internal DataTable GetTableSmart(string name, string ns){
            int fCount = 0; 
            DataTable fTable = null; 
            for (int i = 0; i < _list.Count; i++) {
                DataTable   table = (DataTable) _list[i]; 
                if (table.TableName == name) {
                    if (table.Namespace == ns)
                        return table;
                    fCount++; 
                    fTable = table;
                } 
            } 
            // if we get here we didn't match the namespace
            // so return the table only if fCount==1 (it's the only one) 
            return (fCount == 1) ? fTable : null;
        }
        /// 
        ///     
        ///       Adds
        ///       the specified table to the collection. 
        ///     
        /// 
        public void Add(DataTable table) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, table=%d\n", ObjectID, (table!= null) ?  table.ObjectID : 0);
            try {
                OnCollectionChanging(new CollectionChangeEventArgs(CollectionChangeAction.Add, table)); 
                BaseAdd(table);
                ArrayAdd(table); 
 
                if (table.SetLocaleValue(dataSet.Locale, false, false) ||
                    table.SetCaseSensitiveValue(dataSet.CaseSensitive, false, false)) { 
                    table.ResetIndexes();
                }
                OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, table));
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            } 
        }
 
        /// 
        ///    [To be supplied.]
        /// 
        public void AddRange(DataTable[] tables) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                if (dataSet.fInitInProgress) {
                    delayedAddRangeTables = tables; 
                    return;
                }

                if (tables != null) { 
                    foreach(DataTable table in tables) {
                        if (table != null) { 
                            Add(table); 
                        }
                    } 
                }
            }
            finally{
                Bid.ScopeLeave(ref hscp); 
            }
        } 
 
        /// 
        ///     
        ///       Creates a table with the given name and adds it to the
        ///       collection.
        ///    
        ///  
        public DataTable Add(string name) {
            DataTable table = new DataTable(name); 
            // fxcop: new DataTable should inherit the CaseSensitive, Locale, Namespace from DataSet 
            Add(table);
            return table; 
        }

        public DataTable Add(string name, string tableNamespace) {
            DataTable table = new DataTable(name, tableNamespace); 
            // fxcop: new DataTable should inherit the CaseSensitive, Locale from DataSet
            Add(table); 
            return table; 
        }
        ///  
        ///    
        ///       Creates a new table with a default name and adds it to
        ///       the collection.
        ///     
        /// 
        public DataTable Add() { 
            DataTable table = new DataTable(); 
            // fxcop: new DataTable should inherit the CaseSensitive, Locale, Namespace from DataSet
            Add(table); 
            return table;
        }

        ///  
        ///    
        ///       Occurs when the collection is changed. 
        ///     
        /// 
        [ResDescriptionAttribute(Res.collectionChangedEventDescr)] 
        public event CollectionChangeEventHandler CollectionChanged {
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangedDelegate += value; 
            }
            remove { 
                Bid.Trace(" %d#\n", ObjectID); 
                onCollectionChangedDelegate -= value;
            } 
        }

        /// 
        ///    [To be supplied.] 
        /// 
        public event CollectionChangeEventHandler CollectionChanging { 
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangingDelegate += value; 
            }
            remove {
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangingDelegate -= value; 
            }
        } 
 
        /// 
        ///  Adds the table to the tables array. 
        /// 
        private void ArrayAdd(DataTable table) {
            _list.Add(table);
        } 

        ///  
        /// Creates a new default name. 
        /// 
        internal string AssignName() { 
            string newName = null;
            // RAIDBUG: 91671
            while(this.Contains( newName = MakeName(defaultNameIndex)))
                defaultNameIndex++; 
            return newName;
        } 
 
        /// 
        /// Does verification on the table and it's name, and points the table at the dataSet that owns this collection. 
        /// An ArgumentNullException is thrown if this table is null.  An ArgumentException is thrown if this table
        /// already belongs to this collection, belongs to another collection.
        /// A DuplicateNameException is thrown if this collection already has a table with the same
        /// name (case insensitive). 
        /// 
        private void BaseAdd(DataTable table) { 
            if (table == null) 
                throw ExceptionBuilder.ArgumentNull("table");
            if (table.DataSet == dataSet) 
                throw ExceptionBuilder.TableAlreadyInTheDataSet();
            if (table.DataSet != null)
                throw ExceptionBuilder.TableAlreadyInOtherDataSet();
 
            if (table.TableName.Length == 0)
                table.TableName = AssignName(); 
            else { 
                if (NamesEqual(table.TableName, dataSet.DataSetName, false, dataSet.Locale) != 0 && !table.fNestedInDataset)
                   throw ExceptionBuilder.DatasetConflictingName(dataSet.DataSetName); 
                RegisterName(table.TableName, table.Namespace);
            }

            table.SetDataSet(dataSet); 

            //must run thru the document incorporating the addition of this data table 
            //must make sure there is no other schema component which have the same 
            // identity as this table (for example, there must not be a table with the
            // same identity as a column in this schema. 
        }

        /// 
        /// BaseGroupSwitch will intelligently remove and add tables from the collection. 
        /// 
        private void BaseGroupSwitch(DataTable[] oldArray, int oldLength, DataTable[] 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. 
                    if (oldArray[oldCur].DataSet == dataSet) { 
                        BaseRemove(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].DataSet != dataSet) { 
                    BaseAdd(newArray[newCur]); 
                    _list.Add(newArray[newCur]);
                } 
            }
        }

        ///  
        /// Does verification on the table and it's name, and clears the table's dataSet pointer.
        /// An ArgumentNullException is thrown if this table is null.  An ArgumentException is thrown 
        /// if this table doesn't belong to this collection or if this table is part of a relationship. 
        /// 
        private void BaseRemove(DataTable table) { 
            if (CanRemove(table, true)) {
                UnregisterName(table.TableName);
                table.SetDataSet(null);
 
            }
            _list.Remove(table); 
            dataSet.OnRemovedTable(table); 
        }
 
        /// 
        ///    
        ///       Verifies if a given table can be removed from the collection.
        ///     
        /// 
        public bool CanRemove(DataTable table) { 
            return CanRemove(table, false); 
        }
 
        internal bool CanRemove(DataTable table, bool fThrowException) {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, table=%d, fThrowException=%d{bool}\n", ObjectID, (table != null)? table.ObjectID : 0 , fThrowException);
            try { 
                if (table == null) {
                    if (!fThrowException) 
                        return false; 
                    else
                        throw ExceptionBuilder.ArgumentNull("table"); 
                }
                if (table.DataSet != dataSet) {
                    if (!fThrowException)
                        return false; 
                    else
                        throw ExceptionBuilder.TableNotInTheDataSet(table.TableName); 
                } 

                // allow subclasses to throw. 
                dataSet.OnRemoveTable(table);

                if (table.ChildRelations.Count != 0 || table.ParentRelations.Count != 0) {
                    if (!fThrowException) 
                        return false;
                    else 
                        throw ExceptionBuilder.TableInRelation(); 
                }
 
                for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, table); constraints.GetNext();) {
                    ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint();
                    if (constraint.Table == table && constraint.RelatedTable == table) // we can go with (constraint.Table ==  constraint.RelatedTable)
                        continue; 
                    if (!fThrowException)
                        return false; 
                    else 
                        throw ExceptionBuilder.TableInConstraint(table, constraint);
                } 

                for (ChildForeignKeyConstraintEnumerator constraints = new ChildForeignKeyConstraintEnumerator(dataSet, table); constraints.GetNext();) {
                    ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint();
                    if (constraint.Table == table && constraint.RelatedTable == table) // bug 97670 
                        continue;
 
                    if (!fThrowException) 
                        return false;
                    else 
                        throw ExceptionBuilder.TableInConstraint(table, constraint);
                }

                return true; 
            }
            finally{ 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        /// 
        ///    
        ///       Clears the collection of any tables. 
        ///    
        ///  
        public void Clear() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                int oldLength = _list.Count;
                DataTable[] tables = new DataTable[_list.Count];
                _list.CopyTo(tables, 0); 

                OnCollectionChanging(RefreshEventArgs); 
 
                if (dataSet.fInitInProgress && delayedAddRangeTables != null) {
                    delayedAddRangeTables = null; 
                }

                BaseGroupSwitch(tables, oldLength, null, 0);
                _list.Clear(); 

                OnCollectionChanged(RefreshEventArgs); 
                } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        ///    
        ///       Checks if a table, specified by name, exists in the collection. 
        ///     
        /// 
        public bool Contains(string name) { 
            return (InternalIndexOf(name) >= 0);
        }

        public bool Contains(string name, string tableNamespace) { 
            if (name == null)
                throw ExceptionBuilder.ArgumentNull("name"); 
 
            if (tableNamespace == null)
                throw ExceptionBuilder.ArgumentNull("tableNamespace"); 

            return (InternalIndexOf(name, tableNamespace) >= 0);
        }
 
        internal bool Contains(string name, string tableNamespace, bool checkProperty, bool caseSensitive) {
            if (!caseSensitive) 
                return (InternalIndexOf(name) >= 0); 

            // Case-Sensitive compare 
            int count = _list.Count;
            for (int i = 0; i < count; i++) {
                DataTable table = (DataTable) _list[i];
                // this may be needed to check wether the cascading is creating some conflicts 
                string ns = checkProperty ? table.Namespace : table.tableNamespace ;
                if (NamesEqual(table.TableName, name, true, dataSet.Locale) == 1 && (ns == tableNamespace)) 
                    return true; 
            }
            return false; 
        }

        internal bool Contains(string name, bool caseSensitive) {
            if (!caseSensitive) 
                return (InternalIndexOf(name) >= 0);
 
            // Case-Sensitive compare 
            int count = _list.Count;
            for (int i = 0; i < count; i++) { 
                DataTable table = (DataTable) _list[i];
                if (NamesEqual(table.TableName, name, true, dataSet.Locale) == 1 )
                    return true;
            } 
            return false;
        } 
 
        public void CopyTo(DataTable[] 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] = (DataTable)_list[i]; 
            }
        } 

        /// 
        ///    
        ///       Returns the index of a specified . 
        ///    
        ///  
        public int IndexOf(DataTable table) { 
            int tableCount = _list.Count;
            for (int i = 0; i < tableCount; ++i) { 
                if (table == (DataTable) _list[i]) {
                    return i;
                }
            } 
            return -1;
        } 
 
        /// 
        ///     
        ///       Returns the index of the
        ///       table with the given name (case insensitive), or -1 if the table
        ///       doesn't exist in the collection.
        ///     
        /// 
        public int IndexOf(string tableName) { 
            int index = InternalIndexOf(tableName); 
            return (index < 0) ? -1 : index;
        } 

        public int IndexOf(string tableName, string tableNamespace) {
            return IndexOf( tableName, tableNamespace, true);
        } 

        internal int IndexOf(string tableName, string tableNamespace, bool chekforNull) { // this should be public! why it is missing? 
            if (chekforNull) { 
                if (tableName == null)
                    throw ExceptionBuilder.ArgumentNull("tableName"); 
                if (tableNamespace == null)
                    throw ExceptionBuilder.ArgumentNull("tableNamespace");
            }
            int index = InternalIndexOf(tableName, tableNamespace); 
            return (index < 0) ? -1 : index;
        } 
 
        internal void ReplaceFromInference(System.Collections.Generic.List tableList) {
            Debug.Assert(_list.Count == tableList.Count, "Both lists should have equal numbers of tables"); 
            _list.Clear();
            _list.AddRange(tableList);
        }
 
        // Return value:
        //      >= 0: find the match 
        //        -1: No match 
        //        -2: At least two matches with different cases
        //        -3: At least two matches with different namespaces 
        internal int InternalIndexOf(string tableName) {
            int cachedI = -1;
            if ((null != tableName) && (0 < tableName.Length)) {
                int count = _list.Count; 
                int result = 0;
                for (int i = 0; i < count; i++) { 
                    DataTable table = (DataTable) _list[i]; 
                    result = NamesEqual(table.TableName, tableName, false, dataSet.Locale);
                    if (result == 1) { 
                        // ok, we have found a table with the same name.
                        // let's see if there are any others with the same name
                        // if any let's return (-3) otherwise...
                        for (int j=i+1;j= 0: find the match
        //        -1: No match 
        //        -2: At least two matches with different cases
        internal int InternalIndexOf(string tableName, string tableNamespace) { 
            int cachedI = -1; 
            if ((null != tableName) && (0 < tableName.Length)) {
                int count = _list.Count; 
                int result = 0;
                for (int i = 0; i < count; i++) {
                    DataTable table = (DataTable) _list[i];
                    result = NamesEqual(table.TableName, tableName, false, dataSet.Locale); 
                    if ((result == 1) && (table.Namespace == tableNamespace))
                        return i; 
 
                    if ((result == -1)  && (table.Namespace == tableNamespace))
                        cachedI = (cachedI == -1) ? i : -2; 
                }
            }
            return cachedI;
 
        }
 
        internal void FinishInitCollection() { 
            if (delayedAddRangeTables != null) {
                foreach(DataTable table in delayedAddRangeTables) { 
                    if (table != null) {
                        Add(table);
                    }
                } 
                delayedAddRangeTables = null;
            } 
        } 

        ///  
        /// Makes a default name with the given index.  e.g. Table1, Table2, ... Tablei
        /// 
        private string MakeName(int index) {
            if (1 == index) { 
                return "Table1";
            } 
            return "Table" + index.ToString(System.Globalization.CultureInfo.InvariantCulture); 
        }
 
        /// 
        ///    
        ///       Raises the  event.
        ///     
        /// 
        private void OnCollectionChanged(CollectionChangeEventArgs ccevent) { 
            if (onCollectionChangedDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangedDelegate(this, ccevent); 
            }
        }

        ///  
        ///    [To be supplied.]
        ///  
        private void OnCollectionChanging(CollectionChangeEventArgs ccevent) { 
            if (onCollectionChangingDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onCollectionChangingDelegate(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 Table.TableName property. 
        /// if the name is equivalent to the next default name to hand out, we increment our defaultNameIndex.
        ///  
        internal void RegisterName(string name, string tbNamespace) {
            Bid.Trace(" %d#, name='%ls', tbNamespace='%ls'\n", ObjectID, name, tbNamespace);
            Debug.Assert (name != null);
 
            CultureInfo locale = dataSet.Locale;
            int tableCount = _list.Count; 
            for (int i = 0; i < tableCount; i++) { 
                DataTable table = (DataTable) _list[i];
                if (NamesEqual(name, table.TableName, true, locale) != 0 && (tbNamespace == table.Namespace)) { 
                    throw ExceptionBuilder.DuplicateTableName(((DataTable) _list[i]).TableName);
                }
            }
            if (NamesEqual(name, MakeName(defaultNameIndex), true, locale) != 0) { 
                defaultNameIndex++;
            } 
        } 

        ///  
        ///    
        ///       Removes the specified table from the collection.
        ///    
        ///  
        public void Remove(DataTable table) {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, table=%d\n", ObjectID, (table != null) ? table.ObjectID : 0); 
            try {
                OnCollectionChanging(new CollectionChangeEventArgs(CollectionChangeAction.Remove, table)); 
                BaseRemove(table);
                OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, table));
            }
            finally{ 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        ///  
        ///    
        ///       Removes the
        ///       table at the given index from the collection
        ///     
        /// 
        public void RemoveAt(int index) { 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, index=%d\n", ObjectID, index);
            try { 
                DataTable dt = this[index];
                if (dt == null)
                    throw ExceptionBuilder.TableOutOfRange(index);
                Remove(dt); 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        /// 
        ///    
        ///       Removes the table with a specified name from the 
        ///       collection.
        ///     
        ///  
        public void Remove(string name) {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, name='%ls'\n", ObjectID, name);
            try {
                DataTable dt = this[name];
                if (dt == null) 
                    throw ExceptionBuilder.TableNotInTheDataSet(name);
                Remove(dt); 
            } 
            finally{
                Bid.ScopeLeave(ref hscp); 
            }
        }

        public void Remove(string name, string tableNamespace) { 
            if (name == null)
                throw ExceptionBuilder.ArgumentNull("name"); 
            if (tableNamespace == null) 
                throw ExceptionBuilder.ArgumentNull("tableNamespace");
            DataTable dt = this[name, tableNamespace]; 
            if (dt == null)
                throw ExceptionBuilder.TableNotInTheDataSet(name);
            Remove(dt);
        } 

 
        ///  
        /// Unregisters this name as no longer being used in the collection.  Called by Remove, All property, and
        /// Table.TableName 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) {
            Bid.Trace(" %d#, name='%ls'\n", ObjectID, name); 
            if (NamesEqual(name, MakeName(defaultNameIndex - 1), true, dataSet.Locale) != 0) {
                do { 
                    defaultNameIndex--; 
                } while (defaultNameIndex > 1 &&
                         !Contains(MakeName(defaultNameIndex - 1))); 
            }
        }
    }
} 

// 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; 
    using System.Globalization;
 
    ///  
    ///    
    ///       Represents the collection of tables for the . 
    ///    
    /// 
    [
    DefaultEvent("CollectionChanged"), 
    Editor("Microsoft.VSDesigner.Data.Design.TablesCollectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
    ListBindable(false), 
    ] 
    public sealed class DataTableCollection : InternalDataCollectionBase {
 
        private readonly DataSet dataSet      = null;
        // private DataTable[] tables   = new DataTable[2];
        // private int tableCount       = 0;
        private readonly ArrayList _list = new ArrayList(); 
        private int defaultNameIndex = 1;
        private DataTable[] delayedAddRangeTables = null; 
 
        private CollectionChangeEventHandler onCollectionChangedDelegate = null;
        private CollectionChangeEventHandler onCollectionChangingDelegate = null; 

        private static int _objectTypeCount; // Bid counter
        private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
 
        /// 
        /// DataTableCollection constructor.  Used only by DataSet. 
        ///  
        internal DataTableCollection(DataSet dataSet) {
            Bid.Trace(" %d#, dataSet=%d\n", ObjectID, (dataSet != null) ? dataSet.ObjectID : 0); 
            this.dataSet = dataSet;
        }

        ///  
        ///    
        ///       Gets the tables 
        ///       in the collection as an object. 
        ///    
        ///  
        protected override ArrayList List {
            get {
                return _list;
            } 
        }
 
        internal int ObjectID { 
            get {
                return _objectID; 
            }
        }

        ///  
        ///    Gets the table specified by its index.
        ///  
        public DataTable this[int index] { 
            get {
                try { // Perf: use the readonly _list field directly and let ArrayList check the range 
                    return(DataTable) _list[index];
                }
                catch(ArgumentOutOfRangeException) {
                    throw ExceptionBuilder.TableOutOfRange(index); 
                }
            } 
        } 

        ///  
        ///    Gets the table in the collection with the given name (not case-sensitive).
        /// 
        public DataTable this[string name] {
            get { 
                int index = InternalIndexOf(name);
                if (index == -2) { 
                    throw ExceptionBuilder.CaseInsensitiveNameConflict(name); 
                }
                if (index == -3) { 
                    throw ExceptionBuilder.NamespaceNameConflict(name);
                }
                return (index < 0) ? null : (DataTable)_list[index];
            } 
        }
 
        public DataTable this[string name, string tableNamespace] { 
            get {
                if (tableNamespace == null) 
                    throw ExceptionBuilder.ArgumentNull("tableNamespace");
                int index = InternalIndexOf(name, tableNamespace);
                if (index == -2) {
                    throw ExceptionBuilder.CaseInsensitiveNameConflict(name); 
                }
                return (index < 0) ? null : (DataTable)_list[index]; 
            } 
        }
 
        // Case-sensitive search in Schema, data and diffgram loading
        internal DataTable GetTable(string name, string ns)
        {
            for (int i = 0; i < _list.Count; i++) { 
                DataTable   table = (DataTable) _list[i];
                if (table.TableName == name && table.Namespace == ns) 
                    return table; 
            }
            return null; 
        }

        // Case-sensitive smart search: it will look for a table using the ns only if required to
        // resolve a conflict 
        internal DataTable GetTableSmart(string name, string ns){
            int fCount = 0; 
            DataTable fTable = null; 
            for (int i = 0; i < _list.Count; i++) {
                DataTable   table = (DataTable) _list[i]; 
                if (table.TableName == name) {
                    if (table.Namespace == ns)
                        return table;
                    fCount++; 
                    fTable = table;
                } 
            } 
            // if we get here we didn't match the namespace
            // so return the table only if fCount==1 (it's the only one) 
            return (fCount == 1) ? fTable : null;
        }
        /// 
        ///     
        ///       Adds
        ///       the specified table to the collection. 
        ///     
        /// 
        public void Add(DataTable table) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, table=%d\n", ObjectID, (table!= null) ?  table.ObjectID : 0);
            try {
                OnCollectionChanging(new CollectionChangeEventArgs(CollectionChangeAction.Add, table)); 
                BaseAdd(table);
                ArrayAdd(table); 
 
                if (table.SetLocaleValue(dataSet.Locale, false, false) ||
                    table.SetCaseSensitiveValue(dataSet.CaseSensitive, false, false)) { 
                    table.ResetIndexes();
                }
                OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, table));
            } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            } 
        }
 
        /// 
        ///    [To be supplied.]
        /// 
        public void AddRange(DataTable[] tables) { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try { 
                if (dataSet.fInitInProgress) {
                    delayedAddRangeTables = tables; 
                    return;
                }

                if (tables != null) { 
                    foreach(DataTable table in tables) {
                        if (table != null) { 
                            Add(table); 
                        }
                    } 
                }
            }
            finally{
                Bid.ScopeLeave(ref hscp); 
            }
        } 
 
        /// 
        ///     
        ///       Creates a table with the given name and adds it to the
        ///       collection.
        ///    
        ///  
        public DataTable Add(string name) {
            DataTable table = new DataTable(name); 
            // fxcop: new DataTable should inherit the CaseSensitive, Locale, Namespace from DataSet 
            Add(table);
            return table; 
        }

        public DataTable Add(string name, string tableNamespace) {
            DataTable table = new DataTable(name, tableNamespace); 
            // fxcop: new DataTable should inherit the CaseSensitive, Locale from DataSet
            Add(table); 
            return table; 
        }
        ///  
        ///    
        ///       Creates a new table with a default name and adds it to
        ///       the collection.
        ///     
        /// 
        public DataTable Add() { 
            DataTable table = new DataTable(); 
            // fxcop: new DataTable should inherit the CaseSensitive, Locale, Namespace from DataSet
            Add(table); 
            return table;
        }

        ///  
        ///    
        ///       Occurs when the collection is changed. 
        ///     
        /// 
        [ResDescriptionAttribute(Res.collectionChangedEventDescr)] 
        public event CollectionChangeEventHandler CollectionChanged {
            add {
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangedDelegate += value; 
            }
            remove { 
                Bid.Trace(" %d#\n", ObjectID); 
                onCollectionChangedDelegate -= value;
            } 
        }

        /// 
        ///    [To be supplied.] 
        /// 
        public event CollectionChangeEventHandler CollectionChanging { 
            add { 
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangingDelegate += value; 
            }
            remove {
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangingDelegate -= value; 
            }
        } 
 
        /// 
        ///  Adds the table to the tables array. 
        /// 
        private void ArrayAdd(DataTable table) {
            _list.Add(table);
        } 

        ///  
        /// Creates a new default name. 
        /// 
        internal string AssignName() { 
            string newName = null;
            // RAIDBUG: 91671
            while(this.Contains( newName = MakeName(defaultNameIndex)))
                defaultNameIndex++; 
            return newName;
        } 
 
        /// 
        /// Does verification on the table and it's name, and points the table at the dataSet that owns this collection. 
        /// An ArgumentNullException is thrown if this table is null.  An ArgumentException is thrown if this table
        /// already belongs to this collection, belongs to another collection.
        /// A DuplicateNameException is thrown if this collection already has a table with the same
        /// name (case insensitive). 
        /// 
        private void BaseAdd(DataTable table) { 
            if (table == null) 
                throw ExceptionBuilder.ArgumentNull("table");
            if (table.DataSet == dataSet) 
                throw ExceptionBuilder.TableAlreadyInTheDataSet();
            if (table.DataSet != null)
                throw ExceptionBuilder.TableAlreadyInOtherDataSet();
 
            if (table.TableName.Length == 0)
                table.TableName = AssignName(); 
            else { 
                if (NamesEqual(table.TableName, dataSet.DataSetName, false, dataSet.Locale) != 0 && !table.fNestedInDataset)
                   throw ExceptionBuilder.DatasetConflictingName(dataSet.DataSetName); 
                RegisterName(table.TableName, table.Namespace);
            }

            table.SetDataSet(dataSet); 

            //must run thru the document incorporating the addition of this data table 
            //must make sure there is no other schema component which have the same 
            // identity as this table (for example, there must not be a table with the
            // same identity as a column in this schema. 
        }

        /// 
        /// BaseGroupSwitch will intelligently remove and add tables from the collection. 
        /// 
        private void BaseGroupSwitch(DataTable[] oldArray, int oldLength, DataTable[] 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. 
                    if (oldArray[oldCur].DataSet == dataSet) { 
                        BaseRemove(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].DataSet != dataSet) { 
                    BaseAdd(newArray[newCur]); 
                    _list.Add(newArray[newCur]);
                } 
            }
        }

        ///  
        /// Does verification on the table and it's name, and clears the table's dataSet pointer.
        /// An ArgumentNullException is thrown if this table is null.  An ArgumentException is thrown 
        /// if this table doesn't belong to this collection or if this table is part of a relationship. 
        /// 
        private void BaseRemove(DataTable table) { 
            if (CanRemove(table, true)) {
                UnregisterName(table.TableName);
                table.SetDataSet(null);
 
            }
            _list.Remove(table); 
            dataSet.OnRemovedTable(table); 
        }
 
        /// 
        ///    
        ///       Verifies if a given table can be removed from the collection.
        ///     
        /// 
        public bool CanRemove(DataTable table) { 
            return CanRemove(table, false); 
        }
 
        internal bool CanRemove(DataTable table, bool fThrowException) {
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#, table=%d, fThrowException=%d{bool}\n", ObjectID, (table != null)? table.ObjectID : 0 , fThrowException);
            try { 
                if (table == null) {
                    if (!fThrowException) 
                        return false; 
                    else
                        throw ExceptionBuilder.ArgumentNull("table"); 
                }
                if (table.DataSet != dataSet) {
                    if (!fThrowException)
                        return false; 
                    else
                        throw ExceptionBuilder.TableNotInTheDataSet(table.TableName); 
                } 

                // allow subclasses to throw. 
                dataSet.OnRemoveTable(table);

                if (table.ChildRelations.Count != 0 || table.ParentRelations.Count != 0) {
                    if (!fThrowException) 
                        return false;
                    else 
                        throw ExceptionBuilder.TableInRelation(); 
                }
 
                for (ParentForeignKeyConstraintEnumerator constraints = new ParentForeignKeyConstraintEnumerator(dataSet, table); constraints.GetNext();) {
                    ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint();
                    if (constraint.Table == table && constraint.RelatedTable == table) // we can go with (constraint.Table ==  constraint.RelatedTable)
                        continue; 
                    if (!fThrowException)
                        return false; 
                    else 
                        throw ExceptionBuilder.TableInConstraint(table, constraint);
                } 

                for (ChildForeignKeyConstraintEnumerator constraints = new ChildForeignKeyConstraintEnumerator(dataSet, table); constraints.GetNext();) {
                    ForeignKeyConstraint constraint = constraints.GetForeignKeyConstraint();
                    if (constraint.Table == table && constraint.RelatedTable == table) // bug 97670 
                        continue;
 
                    if (!fThrowException) 
                        return false;
                    else 
                        throw ExceptionBuilder.TableInConstraint(table, constraint);
                }

                return true; 
            }
            finally{ 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        /// 
        ///    
        ///       Clears the collection of any tables. 
        ///    
        ///  
        public void Clear() { 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); 
            try {
                int oldLength = _list.Count;
                DataTable[] tables = new DataTable[_list.Count];
                _list.CopyTo(tables, 0); 

                OnCollectionChanging(RefreshEventArgs); 
 
                if (dataSet.fInitInProgress && delayedAddRangeTables != null) {
                    delayedAddRangeTables = null; 
                }

                BaseGroupSwitch(tables, oldLength, null, 0);
                _list.Clear(); 

                OnCollectionChanged(RefreshEventArgs); 
                } 
            finally {
                Bid.ScopeLeave(ref hscp); 
            }
        }

        ///  
        ///    
        ///       Checks if a table, specified by name, exists in the collection. 
        ///     
        /// 
        public bool Contains(string name) { 
            return (InternalIndexOf(name) >= 0);
        }

        public bool Contains(string name, string tableNamespace) { 
            if (name == null)
                throw ExceptionBuilder.ArgumentNull("name"); 
 
            if (tableNamespace == null)
                throw ExceptionBuilder.ArgumentNull("tableNamespace"); 

            return (InternalIndexOf(name, tableNamespace) >= 0);
        }
 
        internal bool Contains(string name, string tableNamespace, bool checkProperty, bool caseSensitive) {
            if (!caseSensitive) 
                return (InternalIndexOf(name) >= 0); 

            // Case-Sensitive compare 
            int count = _list.Count;
            for (int i = 0; i < count; i++) {
                DataTable table = (DataTable) _list[i];
                // this may be needed to check wether the cascading is creating some conflicts 
                string ns = checkProperty ? table.Namespace : table.tableNamespace ;
                if (NamesEqual(table.TableName, name, true, dataSet.Locale) == 1 && (ns == tableNamespace)) 
                    return true; 
            }
            return false; 
        }

        internal bool Contains(string name, bool caseSensitive) {
            if (!caseSensitive) 
                return (InternalIndexOf(name) >= 0);
 
            // Case-Sensitive compare 
            int count = _list.Count;
            for (int i = 0; i < count; i++) { 
                DataTable table = (DataTable) _list[i];
                if (NamesEqual(table.TableName, name, true, dataSet.Locale) == 1 )
                    return true;
            } 
            return false;
        } 
 
        public void CopyTo(DataTable[] 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] = (DataTable)_list[i]; 
            }
        } 

        /// 
        ///    
        ///       Returns the index of a specified . 
        ///    
        ///  
        public int IndexOf(DataTable table) { 
            int tableCount = _list.Count;
            for (int i = 0; i < tableCount; ++i) { 
                if (table == (DataTable) _list[i]) {
                    return i;
                }
            } 
            return -1;
        } 
 
        /// 
        ///     
        ///       Returns the index of the
        ///       table with the given name (case insensitive), or -1 if the table
        ///       doesn't exist in the collection.
        ///     
        /// 
        public int IndexOf(string tableName) { 
            int index = InternalIndexOf(tableName); 
            return (index < 0) ? -1 : index;
        } 

        public int IndexOf(string tableName, string tableNamespace) {
            return IndexOf( tableName, tableNamespace, true);
        } 

        internal int IndexOf(string tableName, string tableNamespace, bool chekforNull) { // this should be public! why it is missing? 
            if (chekforNull) { 
                if (tableName == null)
                    throw ExceptionBuilder.ArgumentNull("tableName"); 
                if (tableNamespace == null)
                    throw ExceptionBuilder.ArgumentNull("tableNamespace");
            }
            int index = InternalIndexOf(tableName, tableNamespace); 
            return (index < 0) ? -1 : index;
        } 
 
        internal void ReplaceFromInference(System.Collections.Generic.List tableList) {
            Debug.Assert(_list.Count == tableList.Count, "Both lists should have equal numbers of tables"); 
            _list.Clear();
            _list.AddRange(tableList);
        }
 
        // Return value:
        //      >= 0: find the match 
        //        -1: No match 
        //        -2: At least two matches with different cases
        //        -3: At least two matches with different namespaces 
        internal int InternalIndexOf(string tableName) {
            int cachedI = -1;
            if ((null != tableName) && (0 < tableName.Length)) {
                int count = _list.Count; 
                int result = 0;
                for (int i = 0; i < count; i++) { 
                    DataTable table = (DataTable) _list[i]; 
                    result = NamesEqual(table.TableName, tableName, false, dataSet.Locale);
                    if (result == 1) { 
                        // ok, we have found a table with the same name.
                        // let's see if there are any others with the same name
                        // if any let's return (-3) otherwise...
                        for (int j=i+1;j= 0: find the match
        //        -1: No match 
        //        -2: At least two matches with different cases
        internal int InternalIndexOf(string tableName, string tableNamespace) { 
            int cachedI = -1; 
            if ((null != tableName) && (0 < tableName.Length)) {
                int count = _list.Count; 
                int result = 0;
                for (int i = 0; i < count; i++) {
                    DataTable table = (DataTable) _list[i];
                    result = NamesEqual(table.TableName, tableName, false, dataSet.Locale); 
                    if ((result == 1) && (table.Namespace == tableNamespace))
                        return i; 
 
                    if ((result == -1)  && (table.Namespace == tableNamespace))
                        cachedI = (cachedI == -1) ? i : -2; 
                }
            }
            return cachedI;
 
        }
 
        internal void FinishInitCollection() { 
            if (delayedAddRangeTables != null) {
                foreach(DataTable table in delayedAddRangeTables) { 
                    if (table != null) {
                        Add(table);
                    }
                } 
                delayedAddRangeTables = null;
            } 
        } 

        ///  
        /// Makes a default name with the given index.  e.g. Table1, Table2, ... Tablei
        /// 
        private string MakeName(int index) {
            if (1 == index) { 
                return "Table1";
            } 
            return "Table" + index.ToString(System.Globalization.CultureInfo.InvariantCulture); 
        }
 
        /// 
        ///    
        ///       Raises the  event.
        ///     
        /// 
        private void OnCollectionChanged(CollectionChangeEventArgs ccevent) { 
            if (onCollectionChangedDelegate != null) { 
                Bid.Trace(" %d#\n", ObjectID);
                onCollectionChangedDelegate(this, ccevent); 
            }
        }

        ///  
        ///    [To be supplied.]
        ///  
        private void OnCollectionChanging(CollectionChangeEventArgs ccevent) { 
            if (onCollectionChangingDelegate != null) {
                Bid.Trace(" %d#\n", ObjectID); 
                onCollectionChangingDelegate(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 Table.TableName property. 
        /// if the name is equivalent to the next default name to hand out, we increment our defaultNameIndex.
        ///  
        internal void RegisterName(string name, string tbNamespace) {
            Bid.Trace(" %d#, name='%ls', tbNamespace='%ls'\n", ObjectID, name, tbNamespace);
            Debug.Assert (name != null);
 
            CultureInfo locale = dataSet.Locale;
            int tableCount = _list.Count; 
            for (int i = 0; i < tableCount; i++) { 
                DataTable table = (DataTable) _list[i];
                if (NamesEqual(name, table.TableName, true, locale) != 0 && (tbNamespace == table.Namespace)) { 
                    throw ExceptionBuilder.DuplicateTableName(((DataTable) _list[i]).TableName);
                }
            }
            if (NamesEqual(name, MakeName(defaultNameIndex), true, locale) != 0) { 
                defaultNameIndex++;
            } 
        } 

        ///  
        ///    
        ///       Removes the specified table from the collection.
        ///    
        ///  
        public void Remove(DataTable table) {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, table=%d\n", ObjectID, (table != null) ? table.ObjectID : 0); 
            try {
                OnCollectionChanging(new CollectionChangeEventArgs(CollectionChangeAction.Remove, table)); 
                BaseRemove(table);
                OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, table));
            }
            finally{ 
                Bid.ScopeLeave(ref hscp);
            } 
        } 

        ///  
        ///    
        ///       Removes the
        ///       table at the given index from the collection
        ///     
        /// 
        public void RemoveAt(int index) { 
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, index=%d\n", ObjectID, index);
            try { 
                DataTable dt = this[index];
                if (dt == null)
                    throw ExceptionBuilder.TableOutOfRange(index);
                Remove(dt); 
            }
            finally { 
                Bid.ScopeLeave(ref hscp); 
            }
        } 

        /// 
        ///    
        ///       Removes the table with a specified name from the 
        ///       collection.
        ///     
        ///  
        public void Remove(string name) {
            IntPtr hscp; 
            Bid.ScopeEnter(out hscp, " %d#, name='%ls'\n", ObjectID, name);
            try {
                DataTable dt = this[name];
                if (dt == null) 
                    throw ExceptionBuilder.TableNotInTheDataSet(name);
                Remove(dt); 
            } 
            finally{
                Bid.ScopeLeave(ref hscp); 
            }
        }

        public void Remove(string name, string tableNamespace) { 
            if (name == null)
                throw ExceptionBuilder.ArgumentNull("name"); 
            if (tableNamespace == null) 
                throw ExceptionBuilder.ArgumentNull("tableNamespace");
            DataTable dt = this[name, tableNamespace]; 
            if (dt == null)
                throw ExceptionBuilder.TableNotInTheDataSet(name);
            Remove(dt);
        } 

 
        ///  
        /// Unregisters this name as no longer being used in the collection.  Called by Remove, All property, and
        /// Table.TableName 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) {
            Bid.Trace(" %d#, name='%ls'\n", ObjectID, name); 
            if (NamesEqual(name, MakeName(defaultNameIndex - 1), true, dataSet.Locale) != 0) {
                do { 
                    defaultNameIndex--; 
                } while (defaultNameIndex > 1 &&
                         !Contains(MakeName(defaultNameIndex - 1))); 
            }
        }
    }
} 

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