DataTableCollection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Data / System / Data / DataTableCollection.cs / 1 / 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), 
    ] 
#if WINFSInternalOnly
    internal 
#else
    public
#endif
    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), 
    ] 
#if WINFSInternalOnly
    internal 
#else
    public
#endif
    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