DataColumnCollection.cs :  » 2.6.4-mono-.net-core » System.Data » System » Data » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Data 
System.Data » System » Data » DataColumnCollection.cs
//
// System.Data.DataColumnCollection.cs
//
// Author:
//   Christopher Podurgiel (cpodurgiel@msn.com)
//   Stuart Caborn  <stuart.caborn@virgin.net>
//   Tim Coleman (tim@timcoleman.com)
//
// (C) Chris Podurgiel
// Copyright (C) Tim Coleman, 2002
// Copyright (C) Daniel Morgan, 2003
//

//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Text;
using System.Collections;
using System.ComponentModel;

namespace System.Data{

  internal class Doublet
  {
    public Doublet (int count, string columnname)
    {
      this.count = count;
      this.columnNames.Add (columnname);
    }
    // Number of case insensitive column name
    public int count;
    // Array of exact column names
    public ArrayList columnNames = new ArrayList ();
  }

  [Editor ("Microsoft.VSDesigner.Data.Design.ColumnsCollectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner,
     "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
#if !NET_2_0
  [Serializable]
#endif
  [DefaultEvent ("CollectionChanged")]
  public
#if NET_2_0
  sealed
#endif
  class DataColumnCollection : InternalDataCollectionBase  {
    //This hashtable maps between unique case insensetive column name to a doublet containing column ref and column count
#if NET_2_0
    private Hashtable columnNameCount = new Hashtable (StringComparer.OrdinalIgnoreCase);
#else
    private Hashtable columnNameCount = new Hashtable (CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);
#endif
    //This hashtable maps between column name to DataColumn object.
    private Hashtable columnFromName = new Hashtable ();
    //This ArrayList contains the auto-increment columns names
    private ArrayList autoIncrement = new ArrayList ();
    //This holds the next index to use for default column name.
    private int defaultColumnIndex = 1;
    //table should be the DataTable this DataColumnCollection belongs to.
    private DataTable parentTable = null;
    // Keep reference to most recent columns passed to AddRange()
    // so that they can be added when EndInit() is called.
    DataColumn [] _mostRecentColumns = null;

    static readonly string ColumnPrefix = "Column";

    // Internal Constructor.  This Class can only be created from other classes in this assembly.
    internal DataColumnCollection (DataTable table)
    {
      parentTable = table;
    }

    /// <summary>
    /// Gets the DataColumn from the collection at the specified index.
    /// </summary>
    public
#if !NET_2_0
    virtual
#endif
    DataColumn this [int index] {
      get {
        if (index < 0 || index >= base.List.Count)
          throw new IndexOutOfRangeException ("Cannot find column " + index + ".");
        return (DataColumn) base.List [index];
      }
    }

    /// <summary>
    /// Gets the DataColumn from the collection with the specified name.
    /// </summary>
    public
#if !NET_2_0
    virtual
#endif
    DataColumn this [string name] {
      get {
#if NET_2_0
        if (name == null)
          throw new ArgumentNullException ("name");
#endif

        DataColumn dc = columnFromName [name] as DataColumn;
        if (dc != null)
          return dc;

        int tmp = IndexOf (name, true);
        return tmp == -1 ? null : (DataColumn) base.List [tmp];
      }
    }

    /// <summary>
    /// Gets a list of the DataColumnCollection items.
    /// </summary>
    protected override ArrayList List {
      get { return base.List; }
    }

    internal ArrayList AutoIncrmentColumns {
      get { return autoIncrement; }
    }

    //Add Logic
    //
    //Changing Event
    //DefaultValue set and AutoInc set check
    //?Validate Expression??
    //Name check and creation
    //Set Table
    //Check Unique if true then add a unique constraint
    //?Notify Rows of new column ?
    //Add to collection
    //Changed Event

    /// <summary>
    /// Creates and adds a DataColumn object to the DataColumnCollection.
    /// </summary>
    /// <returns></returns>
    public
#if !NET_2_0
    virtual
#endif
    DataColumn Add ()
    {
      DataColumn column = new DataColumn (null);
      Add (column);
      return column;
    }

#if NET_2_0
    public void CopyTo (DataColumn [] array, int index)
    {
      CopyTo ((Array) array, index);
    }
#endif

    internal void RegisterName (string name, DataColumn column)
    {
      try {
        columnFromName.Add (name, column);
      } catch (ArgumentException) {
        throw new DuplicateNameException ("A DataColumn named '" + name + "' already belongs to this DataTable.");
      }

      // Get existing doublet
      Doublet d = (Doublet) columnNameCount [name];
      if (d != null) {
        // Add reference count
        d.count++;
        // Add a new name
        d.columnNames.Add (name);
      } else {
        // no existing doublet
        // create one
        d = new Doublet (1, name);
        columnNameCount [name] = d;
      }

#if NET_2_0
      if (name.Length <= ColumnPrefix.Length || !name.StartsWith (ColumnPrefix, StringComparison.Ordinal))
        return;
#else
      if (name.Length <= ColumnPrefix.Length || !name.StartsWith (ColumnPrefix))
        return;
#endif

      if (name == MakeName (defaultColumnIndex + 1)) {
        do {
          defaultColumnIndex++;
        } while (Contains (MakeName (defaultColumnIndex + 1)));
      }
    }

    internal void UnregisterName (string name)
    {
      if (columnFromName.Contains (name))
        columnFromName.Remove (name);

      // Get the existing doublet
      Doublet d = (Doublet) columnNameCount [name];
      if (d != null) {
        // decrease reference count
        d.count--;
        d.columnNames.Remove (name);
        // remove doublet if no more references
        if (d.count == 0)
          columnNameCount.Remove (name);
      }

      if (name.StartsWith(ColumnPrefix) && name == MakeName(defaultColumnIndex - 1)) {
        do {
          defaultColumnIndex--;
        } while (!Contains (MakeName (defaultColumnIndex - 1)) && defaultColumnIndex > 1);
      }
    }

    private string GetNextDefaultColumnName ()
    {
      string defColumnName = MakeName (defaultColumnIndex);
      for (int index = defaultColumnIndex + 1; Contains (defColumnName); ++index) {
        defColumnName = MakeName (index);
        defaultColumnIndex++;
      }
      defaultColumnIndex++;
      return defColumnName;
    }

    static readonly string[] TenColumns = { "Column0", "Column1", "Column2", "Column3", "Column4", "Column5", "Column6", "Column7", "Column8", "Column9" };

    static string MakeName (int index)
    {
      if (index < 10)
        return TenColumns [index];
      return String.Concat (ColumnPrefix, index.ToString());
    }

    /// <summary>
    /// Creates and adds the specified DataColumn object to the DataColumnCollection.
    /// </summary>
    /// <param name="column">The DataColumn to add.</param>
    public void Add (DataColumn column)
    {
      if (column == null)
        throw new ArgumentNullException ("column", "'column' argument cannot be null.");

#if !NET_2_0
      /* in 1.1, they must do this here, as the
       * setting of ColumnName below causes an event
       * to be raised */
      column.PropertyChanged += new PropertyChangedEventHandler (ColumnPropertyChanged);
#endif

      if (column.ColumnName.Length == 0) {
        column.ColumnName = GetNextDefaultColumnName ();
      }

//      if (Contains(column.ColumnName))
//        throw new DuplicateNameException("A DataColumn named '" + column.ColumnName + "' already belongs to this DataTable.");

      if (column.Table != null)
        throw new ArgumentException ("Column '" + column.ColumnName + "' already belongs to this or another DataTable.");

      column.SetTable (parentTable);
      RegisterName (column.ColumnName, column);
      int ordinal = base.List.Add (column);

#if NET_2_0
      column.Ordinal = ordinal;
#else
      column.SetOrdinal (ordinal);
#endif

      // Check if the Column Expression is ok
      if (column.CompiledExpression != null)
        if (parentTable.Rows.Count == 0)
          column.CompiledExpression.Eval (parentTable.NewRow());
        else
          column.CompiledExpression.Eval (parentTable.Rows[0]);

      // if table already has rows we need to allocate space
      // in the column data container
      if (parentTable.Rows.Count > 0)
        column.DataContainer.Capacity = parentTable.RecordCache.CurrentCapacity;

      if (column.AutoIncrement) {
        DataRowCollection rows = column.Table.Rows;
        for (int i = 0; i < rows.Count; i++)
          rows [i] [ordinal] = column.AutoIncrementValue ();
      }

      if (column.AutoIncrement)
        autoIncrement.Add (column);

#if NET_2_0
      column.PropertyChanged += new PropertyChangedEventHandler (ColumnPropertyChanged);
#endif

      OnCollectionChanged (new CollectionChangeEventArgs(CollectionChangeAction.Add, column));
    }

    /// <summary>
    /// Creates and adds a DataColumn object with the specified name to the DataColumnCollection.
    /// </summary>
    /// <param name="columnName">The name of the column.</param>
    /// <returns>The newly created DataColumn.</returns>
    public
#if !NET_2_0
    virtual
#endif
    DataColumn Add (string columnName)
    {
      DataColumn column = new DataColumn (columnName);
      Add (column);
      return column;
    }

    /// <summary>
    /// Creates and adds a DataColumn object with the specified name and type to the DataColumnCollection.
    /// </summary>
    /// <param name="columnName">The ColumnName to use when cretaing the column.</param>
    /// <param name="type">The DataType of the new column.</param>
    /// <returns>The newly created DataColumn.</returns>
    public
#if !NET_2_0
    virtual
#endif
    DataColumn Add (string columnName, Type type)
    {
      if (columnName == null || columnName == "")
        columnName = GetNextDefaultColumnName ();

      DataColumn column = new DataColumn (columnName, type);
      Add (column);
      return column;
    }

    /// <summary>
    /// Creates and adds a DataColumn object with the specified name, type, and expression to the DataColumnCollection.
    /// </summary>
    /// <param name="columnName">The name to use when creating the column.</param>
    /// <param name="type">The DataType of the new column.</param>
    /// <param name="expression">The expression to assign to the Expression property.</param>
    /// <returns>The newly created DataColumn.</returns>
    public
#if !NET_2_0
    virtual
#endif
    DataColumn Add (string columnName, Type type, string expression)
    {
      if (columnName == null || columnName == "")
        columnName = GetNextDefaultColumnName ();

      DataColumn column = new DataColumn (columnName, type, expression);
      Add (column);
      return column;
    }

    /// <summary>
    /// Copies the elements of the specified DataColumn array to the end of the collection.
    /// </summary>
    /// <param name="columns">The array of DataColumn objects to add to the collection.</param>
    public void AddRange (DataColumn [] columns)
    {
      if (parentTable.InitInProgress){
        _mostRecentColumns = columns;
        return;
      }

      if (columns == null)
        return;

      foreach (DataColumn column in columns){
        if (column == null)
          continue;
        Add(column);
      }
    }

    private string GetColumnDependency (DataColumn column)
    {

      foreach (DataRelation rel in parentTable.ParentRelations)
        if (Array.IndexOf (rel.ChildColumns, column) != -1)
          return String.Format (" child key for relationship {0}.", rel.RelationName);
      foreach (DataRelation rel in parentTable.ChildRelations)
        if (Array.IndexOf (rel.ParentColumns, column) != -1)
          return String.Format (" parent key for relationship {0}.", rel.RelationName);

      foreach (Constraint c in parentTable.Constraints)
        if (c.IsColumnContained (column))
          return String.Format (" constraint {0} on the table {1}.",
              c.ConstraintName, parentTable);


      // check if the foreign-key constraint on any table in the dataset refers to this column.
      // though a forignkeyconstraint automatically creates a uniquecontrainton the parent
      // table and would fail above, but we still need to check, as it is legal to manually remove
      // the constraint on the parent table.
      if (parentTable.DataSet != null)
        foreach (DataTable table in parentTable.DataSet.Tables)
          foreach (Constraint c in table.Constraints)
            if (c is ForeignKeyConstraint && c.IsColumnContained(column))
              return String.Format (
                " constraint {0} on the table {1}.", c.ConstraintName, table.TableName);

      foreach (DataColumn col in this)
        if (col.CompiledExpression != null && col.CompiledExpression.DependsOn (column))
          return  col.Expression;
      return String.Empty;
    }

    /// <summary>
    /// Checks whether a given column can be removed from the collection.
    /// </summary>
    /// <param name="column">A DataColumn in the collection.</param>
    /// <returns>true if the column can be removed; otherwise, false.</returns>
    public bool CanRemove (DataColumn column)
    {
      if (column == null || column.Table != parentTable || GetColumnDependency (column) != String.Empty)
        return false;
      return true;
    }

    /// <summary>
    /// Clears the collection of any columns.
    /// </summary>
    public void Clear ()
    {
      CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this);

      // its not necessary to check if each column in the collection can removed.
      // Can simply check, if there are any constraints/relations related to the table,
      // in which case, throw an exception.
      // Also, shudnt check for expression columns since all the columns in the table
      // are being removed.
      if (parentTable.Constraints.Count != 0 ||
          parentTable.ParentRelations.Count != 0 ||
          parentTable.ChildRelations.Count != 0)
        foreach (DataColumn col in this) {
          string s = GetColumnDependency (col);
          if (s != String.Empty)
            throw new ArgumentException ("Cannot remove this column, because it is part of the" + s);
        }

      if (parentTable.DataSet != null)
        foreach (DataTable table in parentTable.DataSet.Tables)
          foreach (Constraint c in table.Constraints) {
            if (!(c is ForeignKeyConstraint) ||
                ((ForeignKeyConstraint) c).RelatedTable != parentTable)
              continue;
            throw new ArgumentException (
              String.Format (
                "Cannot remove this column, because it is part of the constraint {0} on the table {1}",
                c.ConstraintName, table.TableName));
          }

      foreach (DataColumn col in this)
        col.ResetColumnInfo ();

      columnFromName.Clear ();
      autoIncrement.Clear ();
      columnNameCount.Clear ();
      base.List.Clear ();
      defaultColumnIndex = 1;
      OnCollectionChanged (e);
    }

    /// <summary>
    /// Checks whether the collection contains a column with the specified name.
    /// </summary>
    /// <param name="name">The ColumnName of the column to check for.</param>
    /// <returns>true if a column exists with this name; otherwise, false.</returns>
    public bool Contains (string name)
    {
      if (columnFromName.Contains (name))
        return true;

      return (IndexOf (name, false) != -1);
    }

    /// <summary>
    /// Gets the index of a column specified by name.
    /// </summary>
    /// <param name="column">The name of the column to return.</param>
    /// <returns>The index of the column specified by column if it is found; otherwise, -1.</returns>
    public
#if !NET_2_0
    virtual
#endif
    int IndexOf (DataColumn column)
    {
      if (column == null)
        return -1;
      return base.List.IndexOf (column);
    }

    /// <summary>
    /// Gets the index of the column with the given name (the name is not case sensitive).
    /// </summary>
    /// <param name="columnName">The name of the column to find.</param>
    /// <returns>The zero-based index of the column with the specified name, or -1 if the column doesn't exist in the collection.</returns>
    public int IndexOf (string columnName)
    {
      if (columnName == null)
        return -1;
      DataColumn dc = columnFromName [columnName] as DataColumn;

      if (dc != null)
        return IndexOf (dc);

      return IndexOf (columnName, false);
    }

    /// <summary>
    /// Raises the OnCollectionChanged event.
    /// </summary>
    /// <param name="ccevent">A CollectionChangeEventArgs that contains the event data.</param>
#if !NET_2_0
    protected virtual
#else
    internal
#endif
    void OnCollectionChanged (CollectionChangeEventArgs ccevent)
    {
      parentTable.ResetPropertyDescriptorsCache ();
      if (CollectionChanged != null)
        CollectionChanged (this, ccevent);
    }

    /// <summary>
    /// Raises the OnCollectionChanging event.
    /// </summary>
    /// <param name="ccevent">A CollectionChangeEventArgs that contains the event data.</param>
#if !NET_2_0
    protected internal virtual
#else
    internal
#endif
    void OnCollectionChanging (CollectionChangeEventArgs ccevent)
    {
      if (CollectionChanged != null) {
        //FIXME: this is not right
        //CollectionChanged(this, ccevent);
        throw new NotImplementedException();
      }
    }

    /// <summary>
    /// Removes the specified DataColumn object from the collection.
    /// </summary>
    /// <param name="column">The DataColumn to remove.</param>
    public void Remove (DataColumn column)
    {
      if (column == null)
        throw new ArgumentNullException ("column", "'column' argument cannot be null.");

      if (!Contains (column.ColumnName))
        throw new ArgumentException ("Cannot remove a column that doesn't belong to this table.");

      string dependency = GetColumnDependency (column);
      if (dependency != String.Empty)
        throw new ArgumentException ("Cannot remove this column, because it is part of " + dependency);

      CollectionChangeEventArgs e = new CollectionChangeEventArgs (CollectionChangeAction.Remove, column);

      int ordinal = column.Ordinal;
      UnregisterName (column.ColumnName);
      base.List.Remove (column);

      // Reset column info
      column.ResetColumnInfo ();

      //Update the ordinals
      for( int i = ordinal ; i < this.Count ; i ++ )
#if NET_2_0
        this[i].Ordinal = i;
#else
        this[i].SetOrdinal(i);
#endif

      if (parentTable != null)
        parentTable.OnRemoveColumn (column);

      if (column.AutoIncrement)
        autoIncrement.Remove (column);

      column.PropertyChanged -= new PropertyChangedEventHandler (ColumnPropertyChanged);

      OnCollectionChanged (e);
    }

    /// <summary>
    /// Removes the DataColumn object with the specified name from the collection.
    /// </summary>
    /// <param name="name">The name of the column to remove.</param>
    public void Remove (string name)
    {
      DataColumn column = this [name];

      if (column == null)
        throw new ArgumentException ("Column '" + name + "' does not belong to table " + ( parentTable == null ? "" : parentTable.TableName ) + ".");
      Remove (column);
    }

    /// <summary>
    /// Removes the column at the specified index from the collection.
    /// </summary>
    /// <param name="index">The index of the column to remove.</param>
    public void RemoveAt (int index)
    {
      if (Count <= index)
        throw new IndexOutOfRangeException ("Cannot find column " + index + ".");

      DataColumn column = this [index];
      Remove (column);
    }

    // Helper AddRange() - Call this function when EndInit is called
    internal void PostAddRange ()
    {
      if (_mostRecentColumns == null)
        return;

      foreach (DataColumn column in _mostRecentColumns){
        if (column == null)
          continue;
        Add (column);
      }
      _mostRecentColumns = null;
    }

    internal void UpdateAutoIncrement (DataColumn col,bool isAutoIncrement)
    {
      if (isAutoIncrement) {
        if (!autoIncrement.Contains (col))
          autoIncrement.Add (col);
      } else {
        if (autoIncrement.Contains (col))
          autoIncrement.Remove (col);
      }
    }

    private int IndexOf (string name, bool error)
    {
      // exact case matching has already be done by the caller
      // Get existing doublet
      Doublet d = (Doublet) columnNameCount [name];
      if (d != null) {
        if (d.count == 1) {
          // There's only one
          // return index of the column from the only column name of the doublet
          return base.List.IndexOf (columnFromName [d.columnNames [0]]);
        } else if (d.count > 1 && error) {
          // there's more than one, exception!
          throw new ArgumentException ("There is no match for '" + name + "' in the same case and there are multiple matches in different case.");
        } else {
          return -1;
        }
      }
      return -1;
    }

    #region Events

    /// <summary>
    /// Occurs when the columns collection changes, either by adding or removing a column.
    /// </summary>
    [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")]
    public event CollectionChangeEventHandler CollectionChanged;

    internal event CollectionChangeEventHandler CollectionMetaDataChanged;
    #endregion

    private void OnCollectionMetaDataChanged (CollectionChangeEventArgs ccevent)
    {
      parentTable.ResetPropertyDescriptorsCache ();
      if (CollectionMetaDataChanged != null)
        CollectionMetaDataChanged (this, ccevent);
    }

    private void ColumnPropertyChanged (object sender, PropertyChangedEventArgs args)
    {
      OnCollectionMetaDataChanged (new CollectionChangeEventArgs(CollectionChangeAction.Refresh, sender));
    }

#if NET_2_0
    internal void MoveColumn (int oldOrdinal, int newOrdinal)
    {
      if (newOrdinal == -1 || newOrdinal > this.Count)
        throw new ArgumentOutOfRangeException ("ordinal", "Ordinal '" + newOrdinal + "' exceeds the maximum number.");
      if (oldOrdinal == newOrdinal)
        return;

      int start = newOrdinal > oldOrdinal ? oldOrdinal : newOrdinal;
      int end = newOrdinal > oldOrdinal ?  newOrdinal : oldOrdinal;
      int direction = newOrdinal > oldOrdinal ? 1 : (-1);

      DataColumn currColumn = this [start];
      for (int i = start; i < end; i += direction) {
        List [i] = List [i+direction];
        ((DataColumn) List [i]).Ordinal = i;
      }
      List [end] = currColumn;
      currColumn.Ordinal = end;
    }
#endif
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.