2 // System.Data.DataColumn.cs
\r
5 // Franklin Wise (gracenote@earthlink.net)
\r
6 // Christopher Podurgiel (cpodurgiel@msn.com)
\r
7 // Rodrigo Moya (rodrigo@ximian.com)
\r
8 // Daniel Morgan (danmorg@sc.rr.com)
\r
9 // Tim Coleman (tim@timcoleman.com)
\r
11 // (C) Copyright 2002, Franklin Wise
\r
12 // (C) Chris Podurgiel
\r
13 // (C) Ximian, Inc 2002
\r
14 // Copyright (C) Tim Coleman, 2002
\r
15 // Copyright (C) Daniel Morgan, 2002, 2003
\r
19 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
\r
21 // Permission is hereby granted, free of charge, to any person obtaining
\r
22 // a copy of this software and associated documentation files (the
\r
23 // "Software"), to deal in the Software without restriction, including
\r
24 // without limitation the rights to use, copy, modify, merge, publish,
\r
25 // distribute, sublicense, and/or sell copies of the Software, and to
\r
26 // permit persons to whom the Software is furnished to do so, subject to
\r
27 // the following conditions:
\r
29 // The above copyright notice and this permission notice shall be
\r
30 // included in all copies or substantial portions of the Software.
\r
32 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
33 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
34 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
35 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\r
36 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\r
37 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
38 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
42 using System.ComponentModel;
\r
43 using System.Reflection;
\r
44 using System.Collections;
\r
45 using System.Data.Common;
\r
46 using System.Data.SqlTypes;
\r
47 using System.Globalization;
\r
48 using Mono.Data.SqlExpressions;
\r
50 namespace System.Data {
\r
51 internal delegate void DelegateColumnValueChange (DataColumn column, DataRow row, object proposedValue);
\r
54 /// Summary description for DataColumn.
\r
57 [Editor ("Microsoft.VSDesigner.Data.Design.DataColumnEditor, " + Consts.AssemblyMicrosoft_VSDesigner,
\r
58 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
\r
59 [ToolboxItem (false)]
\r
60 [DefaultProperty ("ColumnName")]
\r
61 [DesignTimeVisible (false)]
\r
62 public class DataColumn : MarshalByValueComponent {
\r
64 EventHandlerList _eventHandlers = new EventHandlerList ();
\r
66 //used for constraint validation
\r
67 //if an exception is fired during this event the change should be canceled
\r
69 //internal event DelegateColumnValueChange ValidateColumnValueChange;
\r
71 //used for FK Constraint Cascading rules
\r
73 //internal event DelegateColumnValueChange ColumnValueChanging;
\r
75 static readonly object _propertyChangedKey = new object ();
\r
76 internal event PropertyChangedEventHandler PropertyChanged {
\r
77 add { _eventHandlers.AddHandler (_propertyChangedKey, value); }
\r
78 remove { _eventHandlers.RemoveHandler (_propertyChangedKey, value); }
\r
85 private bool _allowDBNull = true;
\r
86 private bool _autoIncrement;
\r
87 private long _autoIncrementSeed;
\r
88 private long _autoIncrementStep = 1;
\r
89 private long _nextAutoIncrementValue;
\r
90 private string _caption;
\r
91 private MappingType _columnMapping;
\r
92 private string _columnName = String.Empty;
\r
93 private object _defaultValue = GetDefaultValueForType (null);
\r
94 private string _expression;
\r
95 private IExpression _compiledExpression;
\r
96 private PropertyCollection _extendedProperties = new PropertyCollection ();
\r
97 private int _maxLength = -1; //-1 represents no length limit
\r
98 private string _nameSpace;
\r
99 private int _ordinal = -1; //-1 represents not part of a collection
\r
100 private string _prefix = String.Empty;
\r
101 private bool _readOnly;
\r
102 private DataTable _table;
\r
103 private bool _unique;
\r
104 private DataContainer _dataContainer;
\r
106 #endregion // Fields
\r
108 #region Constructors
\r
110 public DataColumn ()
\r
111 : this (String.Empty, typeof (string), String.Empty, MappingType.Element)
\r
115 //TODO: Ctor init vars directly
\r
116 public DataColumn (string columnName)
\r
117 : this (columnName, typeof (string), String.Empty, MappingType.Element)
\r
121 public DataColumn (string columnName, Type dataType)
\r
122 : this (columnName, dataType, String.Empty, MappingType.Element)
\r
126 public DataColumn (string columnName, Type dataType, string expr)
\r
127 : this (columnName, dataType, expr, MappingType.Element)
\r
131 public DataColumn (string columnName, Type dataType, string expr, MappingType type)
\r
133 ColumnName = columnName == null ? String.Empty : columnName;
\r
135 if (dataType == null)
\r
136 throw new ArgumentNullException ("dataType");
\r
138 DataType = dataType;
\r
139 Expression = expr == null ? String.Empty : expr;
\r
140 ColumnMapping = type;
\r
146 internal object this [int index] {
\r
147 get { return DataContainer [index]; }
\r
149 if (!(value == null && AutoIncrement)) {
\r
151 DataContainer [index] = value;
\r
152 } catch(Exception e) {
\r
153 throw new ArgumentException (
\r
155 "{0}. Couldn't store <{1}> in Column named '{2}'. Expected type is {3}.",
\r
156 e.Message, value, ColumnName, DataType.Name),
\r
161 if (AutoIncrement && !DataContainer.IsNull (index)) {
\r
162 long value64 = Convert.ToInt64 (value);
\r
163 UpdateAutoIncrementValue (value64);
\r
169 DataSetDateTime _datetimeMode = DataSetDateTime.UnspecifiedLocal;
\r
170 [DefaultValue (DataSetDateTime.UnspecifiedLocal)]
\r
171 [RefreshProperties (RefreshProperties.All)]
\r
172 public DataSetDateTime DateTimeMode {
\r
173 get { return _datetimeMode; }
\r
175 if (DataType != typeof (DateTime))
\r
176 throw new InvalidOperationException ("The DateTimeMode can be set only on DataColumns of type DateTime.");
\r
178 if (!Enum.IsDefined (typeof (DataSetDateTime), value))
\r
179 throw new InvalidEnumArgumentException (
\r
181 CultureInfo.InvariantCulture, "The {0} enumeration value, {1}, is invalid",
\r
182 typeof (DataSetDateTime).Name, value));
\r
184 if (_datetimeMode == value)
\r
186 if (_table == null || _table.Rows.Count == 0) {
\r
187 _datetimeMode = value;
\r
190 if ((_datetimeMode == DataSetDateTime.Unspecified || _datetimeMode == DataSetDateTime.UnspecifiedLocal)
\r
191 && (value == DataSetDateTime.Unspecified || value == DataSetDateTime.UnspecifiedLocal)) {
\r
192 _datetimeMode = value;
\r
196 throw new InvalidOperationException (
\r
197 String.Format ("Cannot change DateTimeMode from '{0}' to '{1}' once the table has data.",
\r
198 _datetimeMode, value));
\r
203 [DataCategory ("Data")]
\r
205 [DataSysDescription ("Indicates whether null values are allowed in this column.")]
\r
207 [DefaultValue (true)]
\r
208 public bool AllowDBNull {
\r
209 get { return _allowDBNull; }
\r
211 if (!value && null != _table) {
\r
212 for (int r = 0; r < _table.Rows.Count; r++) {
\r
213 DataRow row = _table.Rows [r];
\r
214 DataRowVersion version = row.HasVersion (DataRowVersion.Default) ?
\r
215 DataRowVersion.Default : DataRowVersion.Original;
\r
216 if (row.IsNull (this, version))
\r
217 throw new DataException ("Column '" + ColumnName + "' has null values in it.");
\r
218 //TODO: do we also check different versions of the row??
\r
222 _allowDBNull = value;
\r
227 /// Gets or sets a value indicating whether the column automatically increments the value of the column for new rows added to the table.
\r
230 /// If the type of this column is not Int16, Int32, or Int64 when this property is set,
\r
231 /// the DataType property is coerced to Int32. An exception is generated if this is a computed column
\r
232 /// (that is, the Expression property is set.) The incremented value is used only if the row's value for this column,
\r
233 /// when added to the columns collection, is equal to the default value.
\r
235 [DataCategory ("Data")]
\r
237 [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.")]
\r
239 [DefaultValue (false)]
\r
240 [RefreshProperties (RefreshProperties.All)]
\r
241 public bool AutoIncrement {
\r
242 get { return _autoIncrement; }
\r
245 //Can't be true if this is a computed column
\r
246 if (Expression != string.Empty)
\r
247 throw new ArgumentException ("Can not Auto Increment a computed column.");
\r
249 if (DefaultValue != DBNull.Value)
\r
250 throw new ArgumentException ("Can not set AutoIncrement while default value exists for this column.");
\r
252 if (!CanAutoIncrement (DataType))
\r
253 DataType = typeof (Int32);
\r
256 if (_table != null)
\r
257 _table.Columns.UpdateAutoIncrement (this, value);
\r
258 _autoIncrement = value;
\r
262 [DataCategory ("Data")]
\r
264 [DataSysDescription ("Indicates the starting value for an AutoIncrement column.")]
\r
267 public long AutoIncrementSeed {
\r
268 get { return _autoIncrementSeed; }
\r
270 _autoIncrementSeed = value;
\r
271 _nextAutoIncrementValue = _autoIncrementSeed;
\r
275 [DataCategory ("Data")]
\r
277 [DataSysDescription ("Indicates the increment used by an AutoIncrement column.")]
\r
280 public long AutoIncrementStep {
\r
281 get { return _autoIncrementStep; }
\r
282 set { _autoIncrementStep = value; }
\r
285 internal void UpdateAutoIncrementValue (long value64)
\r
287 if (_autoIncrementStep > 0) {
\r
288 if (value64 >= _nextAutoIncrementValue) {
\r
289 _nextAutoIncrementValue = value64;
\r
290 AutoIncrementValue ();
\r
292 } else if (value64 <= _nextAutoIncrementValue) {
\r
293 AutoIncrementValue ();
\r
297 internal long AutoIncrementValue ()
\r
299 long currentValue = _nextAutoIncrementValue;
\r
300 _nextAutoIncrementValue += AutoIncrementStep;
\r
301 return currentValue;
\r
304 internal long GetAutoIncrementValue ()
\r
306 return _nextAutoIncrementValue;
\r
309 internal void SetDefaultValue (int index)
\r
312 this [index] = _nextAutoIncrementValue;
\r
314 DataContainer.CopyValue (Table.DefaultValuesRowIndex, index);
\r
317 [DataCategory ("Data")]
\r
319 [DataSysDescription ("Indicates the default user-interface caption for this column.")]
\r
321 public string Caption {
\r
322 get { return _caption == null ? ColumnName : _caption; }
\r
323 set { _caption = value == null ? String.Empty : value; }
\r
327 [DataSysDescription ("Indicates how this column persists in XML: as an attribute, element, simple content node, or nothing.")]
\r
329 [DefaultValue (MappingType.Element)]
\r
330 public virtual MappingType ColumnMapping {
\r
331 get { return _columnMapping; }
\r
332 set { _columnMapping = value; }
\r
335 [DataCategory ("Data")]
\r
337 [DataSysDescription ("Indicates the name used to look up this column in the Columns collection of a DataTable.")]
\r
339 [RefreshProperties (RefreshProperties.All)]
\r
340 [DefaultValue ("")]
\r
341 public string ColumnName {
\r
342 get { return _columnName; }
\r
345 value = String.Empty;
\r
347 CultureInfo info = Table != null ? Table.Locale : CultureInfo.CurrentCulture;
\r
348 if (String.Compare (value, _columnName, true, info) != 0) {
\r
349 if (Table != null) {
\r
350 if (value.Length == 0)
\r
351 throw new ArgumentException ("ColumnName is required when it is part of a DataTable.");
\r
353 Table.Columns.RegisterName (value, this);
\r
354 if (_columnName.Length > 0)
\r
355 Table.Columns.UnregisterName (_columnName);
\r
358 RaisePropertyChanging ("ColumnName");
\r
359 _columnName = value;
\r
362 Table.ResetPropertyDescriptorsCache ();
\r
363 } else if (String.Compare (value, _columnName, false, info) != 0) {
\r
364 RaisePropertyChanging ("ColumnName");
\r
365 _columnName = value;
\r
368 Table.ResetPropertyDescriptorsCache ();
\r
373 [DataCategory ("Data")]
\r
375 [DataSysDescription ("Indicates the type of data stored in this column.")]
\r
377 [DefaultValue (typeof (string))]
\r
378 [RefreshProperties (RefreshProperties.All)]
\r
379 [TypeConverterAttribute (typeof (ColumnTypeConverter))]
\r
380 public Type DataType {
\r
381 get { return DataContainer.Type; }
\r
386 if (_dataContainer != null) {
\r
387 if (value == _dataContainer.Type)
\r
390 // check if data already exists can we change the datatype
\r
391 if (_dataContainer.Capacity > 0)
\r
392 throw new ArgumentException ("The column already has data stored.");
\r
395 if (null != GetParentRelation () || null != GetChildRelation ())
\r
396 throw new InvalidConstraintException ("Cannot change datatype when column is part of a relation");
\r
398 Type prevType = _dataContainer != null ? _dataContainer.Type : null; // current
\r
401 if (_dataContainer != null && _dataContainer.Type == typeof (DateTime))
\r
402 _datetimeMode = DataSetDateTime.UnspecifiedLocal;
\r
404 _dataContainer = DataContainer.Create (value, this);
\r
406 //Check AutoIncrement status, make compatible datatype
\r
407 if(AutoIncrement == true) {
\r
408 // we want to check that the datatype is supported?
\r
409 // TODO: Is this the same as CanAutoIncrement or was the omission of Decimal intended?
\r
410 TypeCode typeCode = Type.GetTypeCode(value);
\r
412 if (typeCode != TypeCode.Int16 &&
\r
413 typeCode != TypeCode.Int32 &&
\r
414 typeCode != TypeCode.Int64) {
\r
415 AutoIncrement = false;
\r
419 if (DefaultValue != GetDefaultValueForType (prevType))
\r
420 SetDefaultValue (DefaultValue, true);
\r
422 _defaultValue = GetDefaultValueForType (DataType);
\r
429 /// <remarks>When AutoIncrement is set to true, there can be no default value.</remarks>
\r
430 /// <exception cref="System.InvalidCastException"></exception>
\r
431 /// <exception cref="System.ArgumentException"></exception>
\r
432 [DataCategory ("Data")]
\r
434 [DataSysDescription ("Indicates the default column value used when adding new rows to the table.")]
\r
436 [TypeConverterAttribute (typeof (System.Data.DefaultValueTypeConverter))]
\r
437 public object DefaultValue {
\r
438 get { return _defaultValue; }
\r
442 throw new ArgumentException ("Can not set default value while AutoIncrement is true on this column.");
\r
443 SetDefaultValue (value, false);
\r
447 void SetDefaultValue (object value, bool forcedTypeCheck)
\r
449 if (forcedTypeCheck || !this._defaultValue.Equals (value)) {
\r
450 if (value == null || value == DBNull.Value)
\r
451 _defaultValue = GetDefaultValueForType (DataType);
\r
452 else if (DataType.IsInstanceOfType (value))
\r
453 _defaultValue = value;
\r
456 _defaultValue = Convert.ChangeType (value, DataType);
\r
457 } catch (InvalidCastException) {
\r
458 string msg = String.Format ("Default Value of type '{0}' is not compatible with column type '{1}'", value.GetType (), DataType);
\r
460 throw new DataException (msg);
\r
462 throw new ArgumentException (msg);
\r
467 // store default value in the table if already belongs to
\r
468 if (Table != null && Table.DefaultValuesRowIndex != -1)
\r
469 DataContainer [Table.DefaultValuesRowIndex] = _defaultValue;
\r
472 [DataCategory ("Data")]
\r
474 [DataSysDescription ("Indicates the value that this column computes for each row based on other columns instead of taking user input.")]
\r
476 [DefaultValue ("")]
\r
477 [RefreshProperties (RefreshProperties.All)]
\r
478 public string Expression {
\r
479 get { return _expression; }
\r
482 value = String.Empty;
\r
484 if (value != String.Empty) {
\r
485 if (AutoIncrement || Unique)
\r
486 throw new ArgumentException ("Cannot create an expression on a column that has AutoIncrement or Unique.");
\r
488 if (Table != null) {
\r
489 for (int i = 0; i < Table.Constraints.Count; i++) {
\r
490 if (Table.Constraints [i].IsColumnContained (this))
\r
491 throw new ArgumentException (
\r
493 "Cannot set Expression property on column {0}, because it is a part of a constraint.",
\r
498 Parser parser = new Parser ();
\r
499 IExpression compiledExpression = parser.Compile (value);
\r
501 if (Table != null) {
\r
502 if (compiledExpression.DependsOn (this))
\r
503 throw new ArgumentException ("Cannot set Expression property due to circular reference in the expression.");
\r
504 // Check if expression is ok
\r
505 if (Table.Rows.Count == 0)
\r
506 compiledExpression.Eval (Table.NewRow ());
\r
508 compiledExpression.Eval (Table.Rows [0]);
\r
511 _compiledExpression = compiledExpression;
\r
513 _compiledExpression = null;
\r
514 if (Table != null) {
\r
515 int defaultValuesRowIndex = Table.DefaultValuesRowIndex;
\r
516 if (defaultValuesRowIndex != -1)
\r
517 DataContainer.FillValues (defaultValuesRowIndex);
\r
520 _expression = value;
\r
524 internal IExpression CompiledExpression {
\r
525 get { return _compiledExpression; }
\r
528 [Browsable (false)]
\r
529 [DataCategory ("Data")]
\r
531 [DataSysDescription ("The collection that holds custom user information.")]
\r
533 public PropertyCollection ExtendedProperties {
\r
534 get { return _extendedProperties; }
\r
536 internal set { _extendedProperties = value; }
\r
540 [DataCategory ("Data")]
\r
542 [DataSysDescription ("Indicates the maximum length of the value this column allows. ")]
\r
544 [DefaultValue (-1)] //Default == -1 no max length
\r
545 public int MaxLength {
\r
546 get { return _maxLength; }
\r
548 if (value >= 0 && _columnMapping == MappingType.SimpleContent)
\r
549 throw new ArgumentException (
\r
551 "Cannot set MaxLength property on '{0}' column which is mapped to SimpleContent.",
\r
553 //only applies to string columns
\r
554 _maxLength = value;
\r
558 [DataCategory ("Data")]
\r
560 [DataSysDescription ("Indicates the XML uri for elements or attributes stored in this column.")]
\r
562 public string Namespace {
\r
564 if (_nameSpace != null)
\r
566 if (Table != null && _columnMapping != MappingType.Attribute)
\r
567 return Table.Namespace;
\r
568 return String.Empty;
\r
570 set { _nameSpace = value; }
\r
573 //Need a good way to set the Ordinal when the column is added to a columnCollection.
\r
574 [Browsable (false)]
\r
575 [DataCategory ("Data")]
\r
577 [DataSysDescription ("Indicates the index of this column in the Columns collection.")]
\r
579 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
580 public int Ordinal {
\r
581 get { return _ordinal; }
\r
583 internal set { _ordinal = value; }
\r
588 public void SetOrdinal (int ordinal)
\r
590 if (_ordinal == -1)
\r
591 throw new ArgumentException ("Column must belong to a table.");
\r
592 _table.Columns.MoveColumn (_ordinal, ordinal);
\r
593 _ordinal = ordinal;
\r
596 internal void SetOrdinal(int ordinal)
\r
598 _ordinal = ordinal;
\r
602 [DataCategory ("Data")]
\r
604 [DataSysDescription ("Indicates the Prefix used for this DataColumn in xml representation.")]
\r
606 [DefaultValue ("")]
\r
607 public string Prefix {
\r
608 get { return _prefix; }
\r
609 set { _prefix = value == null ? String.Empty : value; }
\r
612 [DataCategory ("Data")]
\r
614 [DataSysDescription ("Indicates whether this column allows changes once a row has been added to the table.")]
\r
616 [DefaultValue (false)]
\r
617 public bool ReadOnly {
\r
618 get { return _readOnly; }
\r
619 set { _readOnly = value; }
\r
622 [Browsable (false)]
\r
623 [DataCategory ("Data")]
\r
625 [DataSysDescription ("Returns the DataTable to which this column belongs.")]
\r
627 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
628 public DataTable Table {
\r
629 get { return _table; }
\r
631 internal set { _table = value; }
\r
635 [DataCategory ("Data")]
\r
637 [DataSysDescription ("Indicates whether this column should restrict its values in the rows of the table to be unique.")]
\r
639 [DefaultValue (false)]
\r
640 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
\r
641 public bool Unique {
\r
642 get { return _unique; }
\r
644 if (_unique == value)
\r
647 // Set the property value, so that when adding/removing the constraint
\r
648 // we dont run into recursive issues.
\r
651 if (_table == null)
\r
656 if (Expression != null && Expression != String.Empty)
\r
657 throw new ArgumentException ("Cannot change Unique property for the expression column.");
\r
659 _table.Constraints.Add (null, this, false);
\r
662 UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet (
\r
663 _table.Constraints, new DataColumn[] {this});
\r
664 _table.Constraints.Remove (uc);
\r
666 } catch (Exception e) {
\r
673 internal DataContainer DataContainer {
\r
674 get { return _dataContainer; }
\r
677 internal static bool CanAutoIncrement (Type type)
\r
679 switch (Type.GetTypeCode (type)) {
\r
680 case TypeCode.Int16:
\r
681 case TypeCode.Int32:
\r
682 case TypeCode.Int64:
\r
683 case TypeCode.Decimal:
\r
690 #endregion // Properties
\r
695 internal DataColumn Clone ()
\r
697 DataColumn copy = new DataColumn ();
\r
699 // Copy all the properties of column
\r
700 copy._allowDBNull = _allowDBNull;
\r
701 copy._autoIncrement = _autoIncrement;
\r
702 copy._autoIncrementSeed = _autoIncrementSeed;
\r
703 copy._autoIncrementStep = _autoIncrementStep;
\r
704 copy._caption = _caption;
\r
705 copy._columnMapping = _columnMapping;
\r
706 copy._columnName = _columnName;
\r
708 copy.DataType = DataType;
\r
709 copy._defaultValue = _defaultValue;
\r
710 copy._expression = _expression;
\r
711 //Copy.ExtendedProperties
\r
712 copy._maxLength = _maxLength;
\r
713 copy._nameSpace = _nameSpace;
\r
714 copy._prefix = _prefix;
\r
715 copy._readOnly = _readOnly;
\r
717 //we do not copy the unique value - it will be copyied when copying the constraints.
\r
718 //Copy.Unique = Column.Unique;
\r
720 if (DataType == typeof (DateTime))
\r
721 copy.DateTimeMode = _datetimeMode;
\r
728 /// Sets unique true whithout creating Constraint
\r
730 internal void SetUnique ()
\r
736 internal void AssertCanAddToCollection ()
\r
738 //Check if Default Value is set and AutoInc is set
\r
742 protected internal void CheckNotAllowNull ()
\r
744 throw new NotImplementedException ();
\r
748 protected void CheckUnique ()
\r
750 throw new NotImplementedException ();
\r
753 protected internal virtual void
\r
754 OnPropertyChanging (PropertyChangedEventArgs pcevent)
\r
756 PropertyChangedEventHandler eh = _eventHandlers [_propertyChangedKey] as PropertyChangedEventHandler;
\r
759 eh (this, pcevent);
\r
762 protected internal void RaisePropertyChanging (string name)
\r
764 PropertyChangedEventArgs e = new PropertyChangedEventArgs (name);
\r
765 OnPropertyChanging (e);
\r
769 /// Gets the Expression of the column, if one exists.
\r
771 /// <returns>The Expression value, if the property is set;
\r
772 /// otherwise, the ColumnName property.</returns>
\r
773 public override string ToString ()
\r
775 if (_expression != string.Empty)
\r
776 return ColumnName + " + " + _expression;
\r
781 internal void SetTable (DataTable table)
\r
784 throw new ArgumentException ("The column already belongs to a different table");
\r
787 // this will get called by DataTable
\r
788 // and DataColumnCollection
\r
790 // if the DataColumn is marked as Unique and then
\r
791 // added to a DataTable , then a UniqueConstraint
\r
792 // should be created
\r
793 UniqueConstraint uc = new UniqueConstraint (this);
\r
794 _table.Constraints.Add (uc);
\r
797 // allocate space in the column data container
\r
798 DataContainer.Capacity = _table.RecordCache.CurrentCapacity;
\r
800 int defaultValuesRowIndex = _table.DefaultValuesRowIndex;
\r
801 if (defaultValuesRowIndex != -1) {
\r
802 // store default value in the table
\r
803 DataContainer [defaultValuesRowIndex] = _defaultValue;
\r
804 // Set all the values in data container to default
\r
805 // it's cheaper that raise event on each row.
\r
806 DataContainer.FillValues (defaultValuesRowIndex);
\r
810 // Returns true if all the same collumns are in columnSet and compareSet
\r
811 internal static bool AreColumnSetsTheSame (DataColumn [] columnSet, DataColumn [] compareSet)
\r
813 if (null == columnSet && null == compareSet)
\r
816 if (null == columnSet || null == compareSet)
\r
819 if (columnSet.Length != compareSet.Length)
\r
822 foreach (DataColumn col in columnSet) {
\r
823 bool matchFound = false;
\r
824 foreach (DataColumn compare in compareSet) {
\r
825 if (col == compare)
\r
834 internal int CompareValues (int index1, int index2)
\r
836 return DataContainer.CompareValues (index1, index2);
\r
840 /// Returns the data relation, which contains this column.
\r
841 /// This searches in current table's parent relations.
\r
844 /// DataRelation if found otherwise null.
\r
846 private DataRelation GetParentRelation ()
\r
848 if (_table == null)
\r
850 foreach (DataRelation rel in _table.ParentRelations)
\r
851 if (rel.Contains (this))
\r
858 /// Returns the data relation, which contains this column.
\r
859 /// This searches in current table's child relations.
\r
862 /// DataRelation if found otherwise null.
\r
864 private DataRelation GetChildRelation ()
\r
866 if (_table == null)
\r
868 foreach (DataRelation rel in _table.ChildRelations)
\r
869 if (rel.Contains (this))
\r
874 internal void ResetColumnInfo ()
\r
878 if (_compiledExpression != null)
\r
879 _compiledExpression.ResetExpression ();
\r
882 internal bool DataTypeMatches (DataColumn col)
\r
884 if (DataType != col.DataType)
\r
887 if (DataType != typeof (DateTime))
\r
890 if (DateTimeMode == col.DateTimeMode)
\r
893 if (DateTimeMode == DataSetDateTime.Local || DateTimeMode == DataSetDateTime.Utc)
\r
896 if (col.DateTimeMode == DataSetDateTime.Local || col.DateTimeMode == DataSetDateTime.Utc)
\r
902 internal static object GetDefaultValueForType (Type type)
\r
906 return DBNull.Value;
\r
907 if (type.Namespace == "System.Data.SqlTypes" && type.Assembly == typeof (DataColumn).Assembly) {
\r
908 // For SqlXxx types, set SqlXxx.Null instead of DBNull.Value.
\r
909 if (type == typeof (SqlBinary))
\r
910 return SqlBinary.Null;
\r
911 if (type == typeof (SqlBoolean))
\r
912 return SqlBoolean.Null;
\r
913 if (type == typeof (SqlByte))
\r
914 return SqlByte.Null;
\r
915 if (type == typeof (SqlBytes))
\r
916 return SqlBytes.Null;
\r
917 if (type == typeof (SqlChars))
\r
918 return SqlChars.Null;
\r
919 if (type == typeof (SqlDateTime))
\r
920 return SqlDateTime.Null;
\r
921 if (type == typeof (SqlDecimal))
\r
922 return SqlDecimal.Null;
\r
923 if (type == typeof (SqlDouble))
\r
924 return SqlDouble.Null;
\r
925 if (type == typeof (SqlGuid))
\r
926 return SqlGuid.Null;
\r
927 if (type == typeof (SqlInt16))
\r
928 return SqlInt16.Null;
\r
929 if (type == typeof (SqlInt32))
\r
930 return SqlInt32.Null;
\r
931 if (type == typeof (SqlInt64))
\r
932 return SqlInt64.Null;
\r
933 if (type == typeof (SqlMoney))
\r
934 return SqlMoney.Null;
\r
935 if (type == typeof (SqlSingle))
\r
936 return SqlSingle.Null;
\r
937 if (type == typeof (SqlString))
\r
938 return SqlString.Null;
\r
939 if (type == typeof (SqlXml))
\r
940 return SqlXml.Null;
\r
943 return DBNull.Value;
\r
946 #endregion // Methods
\r