X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=mcs%2Fclass%2FSystem.Data%2FSystem.Data%2FDataColumn.cs;h=afac3af74f378588d915bd253a3896595a841c00;hb=ac27105c704380af358b4c5da005d4efc1e513f4;hp=0032a1395fc7d43bff209329e1befaf446507517;hpb=e3a727ab22cf0054d723692ab6d8cde0fb8b9c7d;p=mono.git diff --git a/mcs/class/System.Data/System.Data/DataColumn.cs b/mcs/class/System.Data/System.Data/DataColumn.cs index 0032a1395fc..afac3af74f3 100644 --- a/mcs/class/System.Data/System.Data/DataColumn.cs +++ b/mcs/class/System.Data/System.Data/DataColumn.cs @@ -1,533 +1,884 @@ -// -// System.Data.DataColumn.cs -// -// Author: -// Franklin Wise (gracenote@earthlink.net) -// Christopher Podurgiel (cpodurgiel@msn.com) -// Rodrigo Moya (rodrigo@ximian.com) -// Daniel Morgan (danmorg@sc.rr.com) -// Tim Coleman (tim@timcoleman.com) -// -// (C) Copyright 2002, Franklin Wise -// (C) Chris Podurgiel -// (C) Ximian, Inc 2002 -// (C) Daniel Morgan 2002 -// Copyright (C) Tim Coleman, 2002 -// - -using System; -using System.ComponentModel; -using System.Reflection; - -namespace System.Data { - internal delegate void DelegateColumnValueChange(DataColumn column, DataRow row, object proposedValue); - - /// - /// Summary description for DataColumn. - /// - - [DefaultMember ("Item")] - [DefaultProperty ("ColumnName")] - [DesignTimeVisible (false)] - public class DataColumn : MarshalByValueComponent - { - #region Events - [MonoTODO] - //used for constraint validation - //if an exception is fired during this event the change should be canceled - internal event DelegateColumnValueChange ValidateColumnValueChange; - - //used for FK Constraint Cascading rules - internal event DelegateColumnValueChange ColumnValueChanging; - #endregion //Events - - #region Fields - - private bool _allowDBNull = true; - private bool _autoIncrement = false; - private long _autoIncrementSeed = 0; - private long _autoIncrementStep = 1; - private string _caption = null; - private MappingType _columnMapping = MappingType.Element; - private string _columnName = null; - private Type _dataType = Type.GetType ("System.String"); - private object _defaultValue = DBNull.Value; - private string expression = ""; - private PropertyCollection _extendedProperties = new PropertyCollection (); - private int maxLength = -1; //-1 represents no length limit - private string nameSpace = ""; - private int _ordinal = -1; //-1 represents not part of a collection - private string prefix = ""; - private bool readOnly = false; - private DataTable _table = null; - private bool unique = false; - - #endregion // Fields - - #region Constructors - - public DataColumn() - { - } - - //TODO: Ctor init vars directly - public DataColumn(string columnName): this() - { - ColumnName = columnName; - } - - public DataColumn(string columnName, Type dataType): this(columnName) - { - if(dataType == null) { - throw new ArgumentNullException("dataType can't be null."); - } - - DataType = dataType; - - } - - public DataColumn( string columnName, Type dataType, - string expr): this(columnName, dataType) - { - Expression = expr; - } - - public DataColumn(string columnName, Type dataType, - string expr, MappingType type): this(columnName, dataType, expr) - { - ColumnMapping = type; - } - #endregion - - #region Properties - - [DataCategory ("Data")] - [DataSysDescription ("Indicates whether null values are allowed in this column.")] - [DefaultValue (true)] - public bool AllowDBNull - { - get { - return _allowDBNull; - } - set { - //TODO: If we are a part of the table and this value changes - //we need to validate that all the existing values conform to the new setting - - if (true == value) - { - _allowDBNull = true; - return; - } - - //if Value == false case - if (null != _table) - { - if (_table.Rows.Count > 0) - { - //TODO: Validate no null values exist - //do we also check different versions of the row?? - } - } - - _allowDBNull = value; - } - } - - /// - /// Gets or sets a value indicating whether the column automatically increments the value of the column for new rows added to the table. - /// - /// - /// If the type of this column is not Int16, Int32, or Int64 when this property is set, - /// the DataType property is coerced to Int32. An exception is generated if this is a computed column - /// (that is, the Expression property is set.) The incremented value is used only if the row's value for this column, - /// when added to the columns collection, is equal to the default value. - /// - [DataCategory ("Data")] - [DataSysDescription ("Indicates whether the column automatically increments itself for new rows added to the table. The type of this column must be Int16, Int32, or Int64.")] - [DefaultValue (false)] - [RefreshProperties (RefreshProperties.All)] - public bool AutoIncrement - { - get { - return _autoIncrement; - } - set { - if(value == true) - { - //Can't be true if this is a computed column - if(Expression != null) - { - throw new ArgumentException("Can't Auto Increment a computed column."); - } - - //If the DataType of this Column isn't an Int - //Make it an int - if(Type.GetTypeCode(_dataType) != TypeCode.Int16 && - Type.GetTypeCode(_dataType) != TypeCode.Int32 && - Type.GetTypeCode(_dataType) != TypeCode.Int64) - { - _dataType = typeof(Int32); - } - } - _autoIncrement = value; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the starting value for an AutoIncrement column.")] - [DefaultValue (0)] - public long AutoIncrementSeed - { - get { - return _autoIncrementSeed; - } - set { - _autoIncrementSeed = value; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the increment used by an AutoIncrement column.")] - [DefaultValue (1)] - public long AutoIncrementStep - { - get { - return _autoIncrementStep; - } - set { - _autoIncrementStep = value; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the default user-interface caption for this column.")] - public string Caption - { - get { - if(_caption == null) - return ColumnName; - else - return _caption; - } - set { - _caption = value; - } - } - [DataSysDescription ("Indicates how this column persists in XML: as an attribute, element, simple content node, or nothing.")] - [DefaultValue (MappingType.Element)] - public virtual MappingType ColumnMapping - { - get { - return _columnMapping; - } - set { - _columnMapping = value; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the name used to look up this column in the Columns collection of a DataTable.")] - [RefreshProperties (RefreshProperties.All)] - public string ColumnName - { - get { - return "" + _columnName; - } - set { - //Both are checked after the column is part of the collection - //TODO: Check Name duplicate - //TODO: check Name != null - _columnName = value; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the type of data stored in this column.")] - [DefaultValue (typeof (string))] - [RefreshProperties (RefreshProperties.All)] - public Type DataType - { - get { - return _dataType; - } - set { - //TODO: check if data already exists can we change the datatype - - //TODO: we want to check that the datatype is supported? - - //Check AutoIncrement status, make compatible datatype - //TODO: Check for other int values i.e. Int16 etc - if(AutoIncrement == true && - Type.GetTypeCode(value) != TypeCode.Int32) - { - throw new Exception(); //TODO: correction exception type - } - _dataType = value; - } - } - - /// - /// - /// - /// When AutoIncrement is set to true, there can be no default value. - /// - /// - [DataCategory ("Data")] - [DataSysDescription ("Indicates the default column value used when adding new rows to the table.")] - public object DefaultValue - { - get { - return _defaultValue; - } - set { - - //If autoIncrement == true throw - if (AutoIncrement) - { - throw new ArgumentException("Can not set default value while" + - " AutoIncrement is true on this column."); - } - - //Will throw invalid cast exception - //if value is not the correct type - //FIXME: some types can be casted - if (value.GetType() != _dataType) - { - throw new InvalidCastException("Default Value type is not compatible with" + - " column type."); - } - - _defaultValue = value; - } - } - - [MonoTODO] - [DataCategory ("Data")] - [DataSysDescription ("Indicates the value that this column computes for each row based on other columns instead of taking user input.")] - [DefaultValue ("")] - [RefreshProperties (RefreshProperties.All)] - public string Expression - { - get { - return expression; - } - set { - //TODO: validation of the expression - expression = value; //Check? - } - } - - [Browsable (false)] - [DataCategory ("Data")] - [DataSysDescription ("The collection that holds custom user information.")] - public PropertyCollection ExtendedProperties - { - get { - return _extendedProperties; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the maximum length of the value this column allows.")] - [DefaultValue (-1)] - public int MaxLength - { - get { - //Default == -1 no max length - return maxLength; - } - set { - //only applies to string columns - maxLength = value; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the XML uri for elements stored in this column.")] - public string Namespace - { - get { - return nameSpace; - } - set { - nameSpace = value; - } - } - - //Need a good way to set the Ordinal when the column is added to a columnCollection. - [Browsable (false)] - [DataCategory ("Data")] - [DataSysDescription ("Indicates the index of this column in the Columns collection.")] - [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] - public int Ordinal - { - get { - //value is -1 if not part of a collection - return _ordinal; - } - } - - internal void SetOrdinal(int ordinal) - { - _ordinal = ordinal; - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates the prefix used for this DataColumn in the xml representation.")] - [DefaultValue ("")] - public string Prefix - { - get { - return prefix; - } - set { - prefix = value; - } - } - - [DataCategory ("Data")] - [DataSysDescription ("Indicates whether this column allows changes once a row has been added to the table.")] - [DefaultValue (false)] - public bool ReadOnly - { - get { - return readOnly; - } - set { - readOnly = value; - } - } - - [Browsable (false)] - [DataCategory ("Data")] - [DataSysDescription ("Returns the DataTable to which this column belongs.")] - [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] - public DataTable Table - { - get { - return _table; - } - } - - [MonoTODO] - [DataCategory ("Data")] - [DataSysDescription ("Indicates whether this column should restrict its values in the rows of the table to be unique.")] - [DefaultValue (false)] - [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] - public bool Unique - { - get { - return unique; - } - set { - //if Table == null then the UniqueConstraint is - //created on addition to the collection - - //FIXME?: need to check if value is the same - //because when calling "new UniqueConstraint" - //the new object tries to set "column.Unique = True" - //which creates an infinite loop. - if(unique != value) - { - unique = value; - - if( value ) - { - if( _table != null ) - { - UniqueConstraint uc = new UniqueConstraint(this); - _table.Constraints.Add(uc); - } - } - else - { - if( _table != null ) - { - //FIXME: Add code to remove constraint from DataTable - throw new NotImplementedException (); - } - } - - } - } - } - - #endregion // Properties - - #region Methods - -/* ?? - [MonoTODO] - protected internal void CheckNotAllowNull() { - } - - [MonoTODO] - protected void CheckUnique() { - } -*/ - - [MonoTODO] - internal void AssertCanAddToCollection() - { - //Check if Default Value is set and AutoInc is set - } - - [MonoTODO] - protected internal virtual void - OnPropertyChanging (PropertyChangedEventArgs pcevent) { - } - - [MonoTODO] - protected internal void RaisePropertyChanging(string name) { - } - - /// - /// Gets the Expression of the column, if one exists. - /// - /// The Expression value, if the property is set; - /// otherwise, the ColumnName property. - [MonoTODO] - public override string ToString() - { - if (expression != null) - return expression; - - return ColumnName; - } - - [MonoTODO] - internal void SetTable(DataTable table) { - _table = table; - // this will get called by DataTable - // and DataColumnCollection - } - - - // Returns true if all the same collumns are in columnSet and compareSet - internal static bool AreColumnSetsTheSame(DataColumn[] columnSet, DataColumn[] compareSet) - { - if (null == columnSet && null == compareSet) return true; - if (null == columnSet || null == compareSet) return false; - - if (columnSet.Length != compareSet.Length) return false; - - foreach (DataColumn col in columnSet) - { - bool matchFound = false; - foreach (DataColumn compare in compareSet) - { - if (col == compare) - { - matchFound = true; - } - } - if (! matchFound) return false; - } - - return true; - } - - #endregion // Methods - - } -} +// +// System.Data.DataColumn.cs +// +// Author: +// Franklin Wise (gracenote@earthlink.net) +// Christopher Podurgiel (cpodurgiel@msn.com) +// Rodrigo Moya (rodrigo@ximian.com) +// Daniel Morgan (danmorg@sc.rr.com) +// Tim Coleman (tim@timcoleman.com) +// +// (C) Copyright 2002, Franklin Wise +// (C) Chris Podurgiel +// (C) Ximian, Inc 2002 +// Copyright (C) Tim Coleman, 2002 +// Copyright (C) Daniel Morgan, 2002, 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.ComponentModel; +using System.Reflection; +using System.Collections; +using System.Data.Common; +using System.Globalization; +using Mono.Data.SqlExpressions; + +namespace System.Data { + internal delegate void DelegateColumnValueChange(DataColumn column, DataRow row, object proposedValue); + + /// + /// Summary description for DataColumn. + /// + + [Editor] + [ToolboxItem (false)] + [DefaultProperty ("ColumnName")] + [DesignTimeVisible (false)] + public class DataColumn : MarshalByValueComponent + { + #region Events + [MonoTODO] + //used for constraint validation + //if an exception is fired during this event the change should be canceled + internal event DelegateColumnValueChange ValidateColumnValueChange; + + //used for FK Constraint Cascading rules + internal event DelegateColumnValueChange ColumnValueChanging; + #endregion //Events + + #region Fields + + private bool _allowDBNull = true; + private bool _autoIncrement; + private long _autoIncrementSeed; + private long _autoIncrementStep = 1; + private long _nextAutoIncrementValue; + private string _caption; + private MappingType _columnMapping; + private string _columnName = String.Empty; + private object _defaultValue = DBNull.Value; + private string _expression; + private IExpression _compiledExpression; + private PropertyCollection _extendedProperties = new PropertyCollection (); + private int _maxLength = -1; //-1 represents no length limit + private string _nameSpace; + private int _ordinal = -1; //-1 represents not part of a collection + private string _prefix = String.Empty; + private bool _readOnly; + private DataTable _table; + private bool _unique; + private AbstractDataContainer _dataContainer; + + #endregion // Fields + + #region Constructors + + public DataColumn() : this(String.Empty, typeof (string), String.Empty, MappingType.Element) + { + } + + //TODO: Ctor init vars directly + public DataColumn(string columnName): this(columnName, typeof (string), String.Empty, MappingType.Element) + { + } + + public DataColumn(string columnName, Type dataType): this(columnName, dataType, String.Empty, MappingType.Element) + { + } + + public DataColumn( string columnName, Type dataType, + string expr): this(columnName, dataType, expr, MappingType.Element) + { + } + + public DataColumn(string columnName, Type dataType, + string expr, MappingType type) + { + ColumnName = (columnName == null ? String.Empty : columnName); + + if(dataType == null) { + throw new ArgumentNullException("dataType can't be null."); + } + + DataType = dataType; + Expression = expr == null ? String.Empty : expr; + ColumnMapping = type; + } + #endregion + + #region Properties + + internal object this[int index] { + get { + return DataContainer[index]; + } + set { + if ( !(value == null && AutoIncrement) ) { + DataContainer[index] = value; + } + + if ( AutoIncrement && !DataContainer.IsNull(index) ) { + long value64 = Convert.ToInt64(value); + UpdateAutoIncrementValue(value64); + } + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates whether null values are allowed in this column.")] + [DefaultValue (true)] + public bool AllowDBNull + { + get { + return _allowDBNull; + } + set { + //TODO: If we are a part of the table and this value changes + //we need to validate that all the existing values conform to the new setting + + if (true == value) + { + _allowDBNull = true; + return; + } + + //if Value == false case + if (null != _table) + { + if (_table.Rows.Count > 0) + { + bool nullsFound = false; + for(int r = 0; r < _table.Rows.Count; r++) { + DataRow row = _table.Rows[r]; + if(row.IsNull(this)) { + nullsFound = true; + break; + } + } + + if (nullsFound) + throw new DataException("Column '" + ColumnName + "' has null values in it."); + //TODO: Validate no null values exist + //do we also check different versions of the row?? + } + } + + _allowDBNull = value; + } + } + + /// + /// Gets or sets a value indicating whether the column automatically increments the value of the column for new rows added to the table. + /// + /// + /// If the type of this column is not Int16, Int32, or Int64 when this property is set, + /// the DataType property is coerced to Int32. An exception is generated if this is a computed column + /// (that is, the Expression property is set.) The incremented value is used only if the row's value for this column, + /// when added to the columns collection, is equal to the default value. + /// + [DataCategory ("Data")] + [DataSysDescription ("Indicates whether the column automatically increments itself for new rows added to the table. The type of this column must be Int16, Int32, or Int64.")] + [DefaultValue (false)] + [RefreshProperties (RefreshProperties.All)] + public bool AutoIncrement + { + get { + return _autoIncrement; + } + set { + if(value == true) + { + //Can't be true if this is a computed column + if (Expression != string.Empty) + { + throw new ArgumentException("Can not Auto Increment a computed column."); + } + + if ( DefaultValue != DBNull.Value ) { + throw new ArgumentException("Can not set AutoIncrement while" + + " default value exists for this column."); + } + + if(!CanAutoIncrement(DataType)) + { + DataType = typeof(Int32); + } + + if (_table != null) + _table.Columns.UpdateAutoIncrement(this,true); + } + else + { + if (_table != null) + _table.Columns.UpdateAutoIncrement(this,false); + } + _autoIncrement = value; + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the starting value for an AutoIncrement column.")] + [DefaultValue (0)] + public long AutoIncrementSeed + { + get { + return _autoIncrementSeed; + } + set { + _autoIncrementSeed = value; + _nextAutoIncrementValue = _autoIncrementSeed; + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the increment used by an AutoIncrement column.")] + [DefaultValue (1)] + public long AutoIncrementStep + { + get { + return _autoIncrementStep; + } + set { + _autoIncrementStep = value; + } + } + + internal void UpdateAutoIncrementValue(long value64) + { + if (_autoIncrementStep > 0 ) { + if (value64 >= _nextAutoIncrementValue) { + _nextAutoIncrementValue = value64; + AutoIncrementValue (); + } + } + else if (value64 <= _nextAutoIncrementValue) { + AutoIncrementValue (); + } + } + + internal long AutoIncrementValue () + { + long currentValue = _nextAutoIncrementValue; + _nextAutoIncrementValue += AutoIncrementStep; + return currentValue; + } + + internal long GetAutoIncrementValue () + { + return _nextAutoIncrementValue; + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the default user-interface caption for this column.")] + public string Caption + { + get { + if(_caption == null) + return ColumnName; + else + return _caption; + } + set { + if (value == null) + value = String.Empty; + + _caption = value; + } + } + [DataSysDescription ("Indicates how this column persists in XML: as an attribute, element, simple content node, or nothing.")] + [DefaultValue (MappingType.Element)] + public virtual MappingType ColumnMapping + { + get { + return _columnMapping; + } + set { + _columnMapping = value; + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the name used to look up this column in the Columns collection of a DataTable.")] + [RefreshProperties (RefreshProperties.All)] + [DefaultValue ("")] + public string ColumnName + { + get { + return _columnName; + } + set { + if (value == null) + value = String.Empty; + + CultureInfo info = Table != null ? Table.Locale : CultureInfo.CurrentCulture; + if (String.Compare(value, _columnName, true, info) != 0) { + if (Table != null) { + if (value.Length == 0) + throw new ArgumentException("ColumnName is required when it is part of a DataTable."); + + Table.Columns.RegisterName(value, this); + if (_columnName.Length > 0) + Table.Columns.UnregisterName(_columnName); + } + + RaisePropertyChanging("ColumnName"); + _columnName = value; + + if (Table != null) + Table.ResetPropertyDescriptorsCache(); + } + else if (String.Compare(value, _columnName, false, info) != 0) { + RaisePropertyChanging("ColumnName"); + _columnName = value; + + if (Table != null) + Table.ResetPropertyDescriptorsCache(); + } + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the type of data stored in this column.")] + [DefaultValue (typeof (string))] + [RefreshProperties (RefreshProperties.All)] + [TypeConverterAttribute (typeof (ColumnTypeConverter))] + public Type DataType + { + get { + return DataContainer.Type; + } + set { + + if ( value == null ) + return; + + if ( _dataContainer != null ) { + if ( value == _dataContainer.Type ) + return; + + // check if data already exists can we change the datatype + if ( _dataContainer.Capacity > 0 ) + throw new ArgumentException("The column already has data stored."); + } + + if (null != GetParentRelation () || null != GetChildRelation ()) + throw new InvalidConstraintException ("Cannot change datatype, " + + "when column is part of a relation"); + + _dataContainer = AbstractDataContainer.CreateInstance(value, this); + + //Check AutoIncrement status, make compatible datatype + if(AutoIncrement == true) { + // we want to check that the datatype is supported? + TypeCode typeCode = Type.GetTypeCode(value); + + if(typeCode != TypeCode.Int16 && + typeCode != TypeCode.Int32 && + typeCode != TypeCode.Int64) { + AutoIncrement = false; + } + } + } + } + + /// + /// + /// + /// When AutoIncrement is set to true, there can be no default value. + /// + /// + [DataCategory ("Data")] + [DataSysDescription ("Indicates the default column value used when adding new rows to the table.")] + [TypeConverterAttribute (typeof (System.Data.DefaultValueTypeConverter))] + public object DefaultValue + { + get { + return _defaultValue; + } + + set { + if (AutoIncrement) { + throw new ArgumentException("Can not set default value while" + + " AutoIncrement is true on this column."); + } + + object tmpObj; + if (!this._defaultValue.Equals(value)) { + if (value == null) { + tmpObj = DBNull.Value; + } + else { + tmpObj = value; + } + + if ((this.DataType != typeof (object))&& (tmpObj != DBNull.Value)) { + try { + //Casting to the new type + tmpObj= Convert.ChangeType(tmpObj,this.DataType); + } + catch (InvalidCastException) { + throw new InvalidCastException("Default Value type is not compatible with" + + " column type."); + } + } + _defaultValue = tmpObj; + } + + // store default value in the table if already belongs to + if (Table != null && Table.DefaultValuesRowIndex != -1) { + DataContainer[Table.DefaultValuesRowIndex] = _defaultValue; + } + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the value that this column computes for each row based on other columns instead of taking user input.")] + [DefaultValue ("")] + [RefreshProperties (RefreshProperties.All)] + public string Expression + { + get { + return _expression; + } + set { + if (value == null) + value = String.Empty; + + if (value != String.Empty) + { + + if (AutoIncrement || Unique) + throw new ArgumentException("Cannot create an expression on a column that has AutoIncrement or Unique."); + + if (Table != null) + { + for (int i = 0; i < Table.Constraints.Count; i++) + { + if (Table.Constraints[i].IsColumnContained(this)) + throw new ArgumentException(String.Format("Cannot set Expression property on column {0}, because it is a part of a constraint.", ColumnName)); + } + } + + Parser parser = new Parser (); + IExpression compiledExpression = parser.Compile (value); + + if (Table != null) + { + if (compiledExpression.DependsOn(this)) + throw new ArgumentException("Cannot set Expression property due to circular reference in the expression."); + } + + ReadOnly = true; + _compiledExpression = compiledExpression; + } + else + { + _compiledExpression = null; + if (Table != null) + { + int defaultValuesRowIndex = Table.DefaultValuesRowIndex; + if ( defaultValuesRowIndex != -1) + DataContainer.FillValues(defaultValuesRowIndex); + } + } + _expression = value; + } + } + + internal IExpression CompiledExpression { + get { return _compiledExpression; } + } + + [Browsable (false)] + [DataCategory ("Data")] + [DataSysDescription ("The collection that holds custom user information.")] + public PropertyCollection ExtendedProperties + { + get { + return _extendedProperties; + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the maximum length of the value this column allows.")] + [DefaultValue (-1)] + public int MaxLength + { + get { + //Default == -1 no max length + return _maxLength; + } + set { + if (value >= 0 && + _columnMapping == MappingType.SimpleContent) + throw new ArgumentException (String.Format ("Cannot set MaxLength property on '{0}' column which is mapped to SimpleContent.", ColumnName)); + //only applies to string columns + _maxLength = value; + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the XML uri for elements stored in this column.")] + public string Namespace + { + get { + if (_nameSpace != null) + { + return _nameSpace; + } + if ((Table != null) && (_columnMapping != MappingType.Attribute)) + { + return Table.Namespace; + } + return String.Empty; + } + set { + _nameSpace = value; + } + } + + //Need a good way to set the Ordinal when the column is added to a columnCollection. + [Browsable (false)] + [DataCategory ("Data")] + [DataSysDescription ("Indicates the index of this column in the Columns collection.")] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public int Ordinal + { + get { + //value is -1 if not part of a collection + return _ordinal; + } + } + + internal void SetOrdinal(int ordinal) + { + _ordinal = ordinal; + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates the prefix used for this DataColumn in the xml representation.")] + [DefaultValue ("")] + public string Prefix + { + get { + return _prefix; + } + set { + if (value == null) + value = String.Empty; + _prefix = value; + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates whether this column allows changes once a row has been added to the table.")] + [DefaultValue (false)] + public bool ReadOnly + { + get { + return _readOnly; + } + set { + _readOnly = value; + } + } + + [Browsable (false)] + [DataCategory ("Data")] + [DataSysDescription ("Returns the DataTable to which this column belongs.")] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public DataTable Table + { + get { + return _table; + } + } + + [DataCategory ("Data")] + [DataSysDescription ("Indicates whether this column should restrict its values in the rows of the table to be unique.")] + [DefaultValue (false)] + [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + public bool Unique + { + get { + return _unique; + } + set { + //NOTE: In .NET 1.1 the Unique property + //is left unchanged when it is added + //to a UniqueConstraint + + if(_unique != value) + { + _unique = value; + + if( value ) + { + if (Expression != null && Expression != String.Empty) + throw new ArgumentException("Cannot change Unique property for the expression column."); + if( _table != null ) + { + UniqueConstraint uc = new UniqueConstraint(this); + _table.Constraints.Add(uc); + } + } + else + { + if( _table != null ) + { + ConstraintCollection cc = _table.Constraints; + //foreach (Constraint c in cc) + for (int i = 0; i < cc.Count; i++) + { + Constraint c = cc[i]; + if (c is UniqueConstraint) + { + DataColumn[] cols = ((UniqueConstraint)c).Columns; + + if (cols.Length == 1 && cols[0] == this) + { + cc.Remove(c); + } + + } + } + } + } + + } + } + } + + internal AbstractDataContainer DataContainer { + get { + return _dataContainer; + } + } + + internal static bool CanAutoIncrement(Type type) { + switch (Type.GetTypeCode(type)) { + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Decimal: + return true; + } + + return false; + } + + #endregion // Properties + + #region Methods + +/* ?? + [MonoTODO] + protected internal void CheckNotAllowNull() { + } + + [MonoTODO] + protected void CheckUnique() { + } +*/ + [MonoTODO] + internal DataColumn Clone() { + DataColumn copy = new DataColumn (); + + // Copy all the properties of column + copy._allowDBNull = _allowDBNull; + copy._autoIncrement = _autoIncrement; + copy._autoIncrementSeed = _autoIncrementSeed; + copy._autoIncrementStep = _autoIncrementStep; + copy._caption = _caption; + copy._columnMapping = _columnMapping; + copy._columnName = _columnName; + //Copy.Container + copy.DataType = DataType; + copy._defaultValue = _defaultValue; + copy._expression = _expression; + //Copy.ExtendedProperties + copy._maxLength = _maxLength; + copy._nameSpace = _nameSpace; + copy._prefix = _prefix; + copy._readOnly = _readOnly; + //Copy.Site + //we do not copy the unique value - it will be copyied when copying the constraints. + //Copy.Unique = Column.Unique; + + return copy; + } + + /// + /// Sets unique true whithout creating Constraint + /// + internal void SetUnique() + { + _unique = true; + } + + [MonoTODO] + internal void AssertCanAddToCollection() + { + //Check if Default Value is set and AutoInc is set + } + + [MonoTODO] + protected internal void CheckNotAllowNull () + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected void CheckUnique () + { + throw new NotImplementedException (); + } + + [MonoTODO] + protected internal virtual void + OnPropertyChanging (PropertyChangedEventArgs pcevent) { + } + + [MonoTODO] + protected internal void RaisePropertyChanging(string name) { + } + + /// + /// Gets the Expression of the column, if one exists. + /// + /// The Expression value, if the property is set; + /// otherwise, the ColumnName property. + public override string ToString() + { + if (_expression != string.Empty) + return ColumnName + " + " + _expression; + + return ColumnName; + } + + internal void SetTable(DataTable table) { + if(_table!=null) { // serves as double check while adding to a table + throw new ArgumentException("The column already belongs to a different table"); + } + _table = table; + // this will get called by DataTable + // and DataColumnCollection + if(_unique) { + // if the DataColumn is marked as Unique and then + // added to a DataTable , then a UniqueConstraint + // should be created + UniqueConstraint uc = new UniqueConstraint(this); + _table.Constraints.Add(uc); + } + + // allocate space in the column data container + DataContainer.Capacity = _table.RecordCache.CurrentCapacity; + + int defaultValuesRowIndex = _table.DefaultValuesRowIndex; + if ( defaultValuesRowIndex != -1) { + // store default value in the table + DataContainer[defaultValuesRowIndex] = _defaultValue; + // Set all the values in data container to default + // it's cheaper that raise event on each row. + DataContainer.FillValues(defaultValuesRowIndex); + } + } + + // Returns true if all the same collumns are in columnSet and compareSet + internal static bool AreColumnSetsTheSame(DataColumn[] columnSet, DataColumn[] compareSet) + { + if (null == columnSet && null == compareSet) { + return true; + } + + if (null == columnSet || null == compareSet) { + return false; + } + + if (columnSet.Length != compareSet.Length) { + return false; + } + + foreach (DataColumn col in columnSet) { + bool matchFound = false; + foreach (DataColumn compare in compareSet) { + if (col == compare) { + matchFound = true; + } + } + if (! matchFound) { + return false; + } + } + return true; + } + + + internal int CompareValues (int index1, int index2) + { + return DataContainer.CompareValues(index1, index2); + } + + /// + /// Returns the data relation, which contains this column. + /// This searches in current table's parent relations. + /// + /// + /// DataRelation if found otherwise null. + /// + private DataRelation GetParentRelation () + { + if (_table == null) + return null; + foreach (DataRelation rel in _table.ParentRelations) + if (rel.Contains (this)) + return rel; + return null; + } + + + /// + /// Returns the data relation, which contains this column. + /// This searches in current table's child relations. + /// + /// + /// DataRelation if found otherwise null. + /// + private DataRelation GetChildRelation () + { + if (_table == null) + return null; + foreach (DataRelation rel in _table.ChildRelations) + if (rel.Contains (this)) + return rel; + return null; + } + + + #endregion // Methods + + } +}