10cda87d34a516e4a987a6eb2ae9e5b994807915
[mono.git] / mcs / class / System.Data / System.Data / DataColumn.cs
1 //
2 // System.Data.DataColumn.cs
3 //
4 // Author:
5 //   Franklin Wise (gracenote@earthlink.net)
6 //   Christopher Podurgiel (cpodurgiel@msn.com)
7 //   Rodrigo Moya (rodrigo@ximian.com)
8 //   Daniel Morgan (danmorg@sc.rr.com)
9 //
10 // (C) Copyright 2002, Franklin Wise
11 // (C) Chris Podurgiel
12 // (C) Ximian, Inc 2002
13 //
14
15
16 using System;
17 using System.ComponentModel;
18
19 namespace System.Data
20 {
21         internal delegate void DelegateColumnValueChange(DataColumn column,
22                         DataRow row, object proposedValue);
23
24         
25         /// <summary>
26         /// Summary description for DataColumn.
27         /// </summary>
28         public class DataColumn : MarshalByValueComponent
29         {               
30                 #region Events
31                 [MonoTODO]
32                 //used for constraint validation
33                 //if an exception is fired during this event the change should be canceled
34                 internal event DelegateColumnValueChange ValidateColumnValueChange;
35
36                 //used for FK Constraint Cascading rules
37                 internal event DelegateColumnValueChange ColumnValueChanging;
38                 #endregion //Events
39
40                 
41                 #region Fields
42
43                 private bool _allowDBNull = true;
44                 private bool _autoIncrement = false;
45                 private long _autoIncrementSeed = 0;
46                 private long _autoIncrementStep = 1;
47                 private string _caption = null;
48                 private MappingType _columnMapping = MappingType.Element;
49                 private string _columnName = null;
50                 private Type _dataType = null;
51                 private object _defaultValue = null;
52                 private string expression = null;
53                 private PropertyCollection _extendedProperties = null;
54                 private int maxLength = -1; //-1 represents no length limit
55                 private string nameSpace = null;
56                 private int _ordinal = -1; //-1 represents not part of a collection
57                 private string prefix = null;
58                 private bool readOnly = false;
59                 private DataTable _table = null;
60                 private bool unique = false;
61
62                 #endregion // Fields
63
64                 #region Constructors
65
66                 public DataColumn()
67                 {
68                 }
69
70                 //TODO: Ctor init vars directly
71                 public DataColumn(string columnName): this()
72                 {
73                         ColumnName = columnName;
74                 }
75
76                 public DataColumn(string columnName, Type dataType): this(columnName)
77                 {
78                         if(dataType == null) {
79                                 throw new ArgumentNullException("dataType can't be null.");
80                         }
81                         
82                         DataType = dataType;
83
84                 }
85
86                 public DataColumn( string columnName, Type dataType, 
87                         string expr): this(columnName, dataType)
88                 {
89                         Expression = expr;
90                 }
91
92                 public DataColumn(string columnName, Type dataType, 
93                         string expr, MappingType type): this(columnName, dataType, expr)
94                 {
95                         ColumnMapping = type;
96                 }
97                 #endregion
98
99                 #region Properties
100                 
101                 public bool AllowDBNull
102                 {
103                         get {
104                                 return _allowDBNull;
105                         }
106                         set {
107                                 //TODO: If we are a part of the table and this value changes
108                                 //we need to validate that all the existing values conform to the new setting
109
110                                 if (true == value)
111                                 {
112                                         _allowDBNull = true;
113                                         return;
114                                 }
115                                 
116                                 //if Value == false case
117                                 if (null != _table)
118                                 {
119                                         if (_table.Rows.Count > 0)
120                                         {
121                                                 //TODO: Validate no null values exist
122                                                 //do we also check different versions of the row??
123                                         }
124                                 }
125                                         
126                                 _allowDBNull = value;
127                         }
128                 }
129         
130                 /// <summary>
131                 /// Gets or sets a value indicating whether the column automatically increments the value of the column for new rows added to the table.
132                 /// </summary>
133                 /// <remarks>
134                 ///             If the type of this column is not Int16, Int32, or Int64 when this property is set, 
135                 ///             the DataType property is coerced to Int32. An exception is generated if this is a computed column 
136                 ///             (that is, the Expression property is set.) The incremented value is used only if the row's value for this column, 
137                 ///             when added to the columns collection, is equal to the default value.
138                 ///     </remarks>
139                 public bool AutoIncrement
140                 {
141                         get {
142                                 return _autoIncrement;
143                         }
144                         set {
145                                 if(value == true)
146                                 {
147                                         //Can't be true if this is a computed column
148                                         if(Expression != null)
149                                         {
150                                                 throw new ArgumentException("Can't Auto Increment a computed column."); 
151                                         }
152
153                                         //If the DataType of this Column isn't an Int
154                                         //Make it an int
155                                         if(Type.GetTypeCode(_dataType) != TypeCode.Int16 && 
156                                            Type.GetTypeCode(_dataType) != TypeCode.Int32 && 
157                                            Type.GetTypeCode(_dataType) != TypeCode.Int64)
158                                         {
159                                                 _dataType = typeof(Int32); 
160                                         }
161                                 }
162                                 _autoIncrement = value;
163                         }
164                 }
165
166                 public long AutoIncrementSeed
167                 {
168                         get {
169                                 return _autoIncrementSeed;
170                         }
171                         set {
172                                 _autoIncrementSeed = value;
173                         }
174                 }
175
176                 public long AutoIncrementStep
177                 {
178                         get {
179                                 return _autoIncrementStep;
180                         }
181                         set {
182                                 _autoIncrementStep = value;
183                         }
184                 }
185
186                 public string Caption 
187                 {
188                         get {
189                                 if(_caption == null)
190                                         return ColumnName;
191                                 else
192                                         return _caption;
193                         }
194                         set {
195                                 _caption = value;
196                         }
197                 }
198
199                 public virtual MappingType ColumnMapping
200                 {
201                         get {
202                                 return _columnMapping;
203                         }
204                         set {
205                                 _columnMapping = value;
206                         }
207                 }
208
209                 public string ColumnName
210                 {
211                         get {
212                                 return "" + _columnName;
213                         }
214                         set {
215                                 //Both are checked after the column is part of the collection
216                                 //TODO: Check Name duplicate
217                                 //TODO: check Name != null
218                                 _columnName = value;
219                         }
220                 }
221
222                 public Type DataType
223                 {
224                         get {
225                                 return _dataType;
226                         }
227                         set {
228                                 //TODO: check if data already exists can we change the datatype
229
230                                 //TODO: we want to check that the datatype is supported?
231                                 
232                                 //Check AutoIncrement status, make compatible datatype
233                                 //TODO: Check for other int values i.e. Int16 etc
234                                 if(AutoIncrement == true && 
235                                    Type.GetTypeCode(value) != TypeCode.Int32)
236                                 {
237                                         throw new Exception(); //TODO: correction exception type
238                                 }
239                                 _dataType = value;
240                         }
241                 }
242
243                 /// <summary>
244                 /// 
245                 /// </summary>
246                 /// <remarks>When AutoIncrement is set to true, there can be no default value.</remarks>
247                 /// <exception cref="System.InvalidCastException"></exception>
248                 /// <exception cref="System.ArgumentException"></exception>
249                 public object DefaultValue
250                 {
251                         get {
252                                 return _defaultValue;
253                         }
254                         set {
255                                 
256                                 //If autoIncrement == true throw
257                                 if (AutoIncrement) 
258                                 {
259                                         throw new ArgumentException("Can not set default value while" +
260                                                         " AutoIncrement is true on this column.");
261                                 }
262                                         
263                                 //Will throw invalid cast exception
264                                 //if value is not the correct type
265                                 //FIXME: some types can be casted
266                                 if (value.GetType() != _dataType)
267                                 {
268                                         throw new InvalidCastException("Default Value type is not compatible with" + 
269                                                         " column type.");
270                                 }
271                                         
272                                 _defaultValue = value;
273                         }
274                 }
275
276                 [MonoTODO]
277                 public string Expression
278                 {
279                         get {
280                                 return expression;
281                         }
282                         set {
283                                 //TODO: validation of the expression
284                                 expression = value;  //Check?
285                         }
286                 }
287
288                 public PropertyCollection ExtendedProperties
289                 {
290                         get {
291                                 return _extendedProperties;
292                         }
293                 }
294
295                 public int MaxLength
296                 {
297                         get {
298                                 //Default == -1 no max length
299                                 return maxLength;
300                         }
301                         set {
302                                 //only applies to string columns
303                                 maxLength = value;
304                         }
305                 }
306
307                 public string Namespace
308                 {
309                         get {
310                                 return nameSpace;
311                         }
312                         set {
313                                 nameSpace = value;
314                         }
315                 }
316
317                 //Need a good way to set the Ordinal when the column is added to a columnCollection.
318                 public int Ordinal
319                 {
320                         get {
321                                 //value is -1 if not part of a collection
322                                 return _ordinal;
323                         }
324                 }
325
326                 internal void SetOrdinal(int ordinal)
327                 {
328                         _ordinal = ordinal;
329                 }
330
331                 public string Prefix
332                 {
333                         get {
334                                 return prefix;
335                         }
336                         set {
337                                 prefix = value;
338                         }
339                 }
340
341                 public bool ReadOnly
342                 {
343                         get {
344                                 return readOnly;
345                         }
346                         set {
347                                 readOnly = value;
348                         }
349                 }
350         
351                 public DataTable Table
352                 {
353                         get {
354                                 return _table;
355                         }
356                 }
357
358                 [MonoTODO]
359                 public bool Unique
360                 {
361                         get {
362                                 return unique;
363                         }
364                         set {
365                                 //TODO: create UniqueConstraint
366                                 //if Table == null then the constraint is 
367                                 //created on addition to the collection
368                                 
369                                 //FIXME?: need to check if value is the same
370                                 //because when calling "new UniqueConstraint"
371                                 //the new object tries to set "column.Unique = True"
372                                 //which creates an infinite loop.
373                                 if(unique != value)
374                                 {
375                                 unique = value;
376
377                                         if( value )
378                                         {
379                                                 if( _table != null )
380                                                 {
381                                                         UniqueConstraint uc = new UniqueConstraint(this);
382                                                         _table.Constraints.Add(uc);
383                                                 }
384                                         }
385                                         else
386                                         {
387                                                 if( _table != null )
388                                                 {
389                                                         //FIXME: Add code to remove constraint from DataTable
390                                                         throw new NotImplementedException ();
391                                                 }
392                                         }
393
394                                 }
395                         }
396                 }
397
398                 #endregion // Properties
399
400                 #region Methods
401                 
402 /* ??
403                 [MonoTODO]
404                 protected internal void CheckNotAllowNull() {
405                 }
406
407                 [MonoTODO]
408                 protected void CheckUnique() {
409                 }
410 */
411
412                 [MonoTODO]
413                 internal void AssertCanAddToCollection()
414                 {
415                         //Check if Default Value is set and AutoInc is set
416                 }
417                 
418                 [MonoTODO]
419                 protected internal virtual void 
420                 OnPropertyChanging (PropertyChangedEventArgs pcevent) {
421                 }
422
423                 [MonoTODO]
424                 protected internal void RaisePropertyChanging(string name) {
425                 }
426
427                 /// <summary>
428                 /// Gets the Expression of the column, if one exists.
429                 /// </summary>
430                 /// <returns>The Expression value, if the property is set; 
431                 /// otherwise, the ColumnName property.</returns>
432                 [MonoTODO]
433                 public override string ToString()
434                 {
435                         if (expression != null)
436                                 return expression;
437                         
438                         return ColumnName;
439                 }
440
441                 [MonoTODO]
442                 internal void SetTable(DataTable table) {
443                         _table = table; 
444                         // this will get called by DataTable 
445                         // and DataColumnCollection
446                 }
447
448                 
449                 // Returns true if all the same collumns are in columnSet and compareSet
450                 internal static bool AreColumnSetsTheSame(DataColumn[] columnSet, DataColumn[] compareSet)
451                 {
452                         if (null == columnSet && null == compareSet) return true;
453                         if (null == columnSet || null == compareSet) return false;
454
455                         if (columnSet.Length != compareSet.Length) return false;
456                         
457                         foreach (DataColumn col in columnSet)
458                         {
459                                 bool matchFound = false;
460                                 foreach (DataColumn compare in compareSet)
461                                 {
462                                         if (col == compare)
463                                         {
464                                                 matchFound = true;                                      
465                                         }
466                                 }
467                                 if (! matchFound) return false;
468                         }
469                         
470                         return true;
471                 }
472                 
473                 #endregion // Methods
474
475         }
476 }