* DataTable.cs: Add rows to the row list if there is
[mono.git] / mcs / class / System.Data / System.Data / DataRow.cs
1 //
2 // System.Data.DataRow.cs
3 //
4 // Author:
5 //   Rodrigo Moya <rodrigo@ximian.com>
6 //   Daniel Morgan <danmorg@sc.rr.com>
7 //   Tim Coleman <tim@timcoleman.com>
8 //   Ville Palo <vi64pa@koti.soon.fi>
9 //   Alan Tam Siu Lung <Tam@SiuLung.com>
10 //
11 // (C) Ximian, Inc 2002
12 // (C) Daniel Morgan 2002, 2003
13 // Copyright (C) 2002 Tim Coleman
14 //
15
16 using System;
17 using System.Collections;
18 using System.Globalization;
19
20 namespace System.Data {
21         /// <summary>
22         /// Represents a row of data in a DataTable.
23         /// </summary>
24         [Serializable]
25         public class DataRow
26         {
27                 #region Fields
28
29                 private DataTable _table;
30
31                 private object[] original;
32                 private object[] proposed;
33                 private object[] current;
34
35                 private string[] columnErrors;
36                 private string rowError;
37                 private DataRowState rowState;
38                 internal int xmlRowID = 0;
39                 internal bool _nullConstraintViolation;
40                 private string _nullConstraintMessage;
41                 private bool editing = false;
42                 private bool _hasParentCollection;
43                 private bool _inChangingEvent;
44                 private int _rowId;
45
46                 #endregion
47
48                 #region Constructors
49
50                 /// <summary>
51                 /// This member supports the .NET Framework infrastructure and is not intended to be 
52                 /// used directly from your code.
53                 /// </summary>
54                 protected internal DataRow (DataRowBuilder builder)
55                 {
56                         _table = builder.Table;
57                         // Get the row id from the builder.
58                         _rowId = builder._rowId;
59
60                         original = null; 
61                         
62                         proposed = new object[_table.Columns.Count];
63                         // Initialise the data coloumns of the row with the dafault values, if any 
64                         for (int c = 0; c < _table.Columns.Count; c++) 
65                         {
66                                 if(_table.Columns [c].DefaultValue == null)
67                                         proposed[c] = DBNull.Value;
68                                 else
69                                         proposed [c] = _table.Columns[c].DefaultValue;
70                         }
71                         
72                         columnErrors = new string[_table.Columns.Count];
73                         rowError = String.Empty;
74
75                         //on first creating a DataRow it is always detached.
76                         rowState = DataRowState.Detached;
77                         
78                         foreach (DataColumn Col in _table.Columns) {
79                                 
80                                 if (Col.AutoIncrement) {
81                                         this [Col] = Col.AutoIncrementValue();
82                                 }
83                         }
84                         _table.Columns.CollectionChanged += new System.ComponentModel.CollectionChangeEventHandler(CollectionChanged);
85                 }
86
87                 
88                 #endregion
89
90                 #region Properties
91
92                 /// <summary>
93                 /// Gets a value indicating whether there are errors in a row.
94                 /// </summary>
95                 public bool HasErrors {
96                         get {
97                                 if (RowError != string.Empty)
98                                         return true;
99
100                                 for (int i= 0; i < columnErrors.Length; i++){
101                                         if (columnErrors[i] != null && columnErrors[i] != string.Empty)
102                                                 return true;
103                                 }
104
105                                 return false;
106                         }
107                 }
108
109                 /// <summary>
110                 /// Gets or sets the data stored in the column specified by name.
111                 /// </summary>
112                 public object this[string columnName] {
113                         get { return this[columnName, DataRowVersion.Default]; }
114                         set {
115                                 int columnIndex = _table.Columns.IndexOf (columnName);
116                                 if (columnIndex == -1)
117                                         throw new IndexOutOfRangeException ();
118                                 this[columnIndex] = value;
119                         }
120                 }
121
122                 /// <summary>
123                 /// Gets or sets the data stored in specified DataColumn
124                 /// </summary>
125                 public object this[DataColumn column] {
126
127                         get {
128                                 return this[column, DataRowVersion.Default];} 
129                         set {
130                                 int columnIndex = _table.Columns.IndexOf (column);
131                                 if (columnIndex == -1)
132                                         throw new ArgumentException ("The column does not belong to this table.");
133                                 this[columnIndex] = value;
134                         }
135                 }
136
137                 /// <summary>
138                 /// Gets or sets the data stored in column specified by index.
139                 /// </summary>
140                 public object this[int columnIndex] {
141                         get { return this[columnIndex, DataRowVersion.Default]; }
142                         set {
143                                 if (columnIndex < 0 || columnIndex > _table.Columns.Count)
144                                         throw new IndexOutOfRangeException ();
145                                 if (rowState == DataRowState.Deleted)
146                                         throw new DeletedRowInaccessibleException ();
147                                 DataColumn column = _table.Columns[columnIndex];
148                                 _table.ChangingDataColumn (this, column, value);
149                                 
150                                 
151                                 bool orginalEditing = editing;
152                                 if (!orginalEditing) BeginEdit ();
153                                 object v = SetColumnValue (value, columnIndex);
154                                 proposed[columnIndex] = v;
155                                 _table.ChangedDataColumn (this, column, v);
156                                 if (!orginalEditing) EndEdit ();
157                         }
158                 }
159
160                 /// <summary>
161                 /// Gets the specified version of data stored in the named column.
162                 /// </summary>
163                 public object this[string columnName, DataRowVersion version] {
164                         get {
165                                 int columnIndex = _table.Columns.IndexOf (columnName);
166                                 if (columnIndex == -1)
167                                         throw new IndexOutOfRangeException ();
168                                 return this[columnIndex, version];
169                         }
170                 }
171
172                 /// <summary>
173                 /// Gets the specified version of data stored in the specified DataColumn.
174                 /// </summary>
175                 public object this[DataColumn column, DataRowVersion version] {
176                         get {
177                                 if (column.Table != Table)
178                                         throw new ArgumentException ("The column does not belong to this table.");
179                                 int columnIndex = column.Ordinal;
180                                 return this[columnIndex, version];
181                         }
182                 }
183
184                 /// <summary>
185                 /// Gets the data stored in the column, specified by index and version of the data to
186                 /// retrieve.
187                 /// </summary>
188                 public object this[int columnIndex, DataRowVersion version] {
189                         get {
190                                 if (columnIndex < 0 || columnIndex > _table.Columns.Count)
191                                         throw new IndexOutOfRangeException ();
192                                 // Accessing deleted rows
193                                 if (rowState == DataRowState.Deleted && version != DataRowVersion.Original)
194                                         throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
195                                 
196                                 DataColumn col = _table.Columns[columnIndex];
197                                 if (col.Expression != String.Empty) {
198                                         object o = col.CompiledExpression.Eval (this);
199                                         return Convert.ChangeType (o, col.DataType);
200                                 }
201                                 
202                                 if (HasVersion(version))
203                                 {
204                                         switch (version) 
205                                         {
206                                                 case DataRowVersion.Default:
207                                                         if (editing || rowState == DataRowState.Detached)
208                                                                 return proposed[columnIndex];
209                                                         return current[columnIndex];
210                                                 case DataRowVersion.Proposed:
211                                                         return proposed[columnIndex];
212                                                 case DataRowVersion.Current:
213                                                         return current[columnIndex];
214                                                 case DataRowVersion.Original:
215                                                         return original[columnIndex];
216                                                 default:
217                                                         throw new ArgumentException ();
218                                         }
219                                 }
220                                 if (rowState == DataRowState.Detached && version == DataRowVersion.Default && proposed == null)
221                                         throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
222                                 
223                                 throw new VersionNotFoundException (Locale.GetText ("There is no " + version.ToString () + " data to access."));
224                         }
225                 }
226                 
227                 internal void SetOriginalValue (string columnName, object val)
228                 {
229                         int columnIndex = _table.Columns.IndexOf (columnName);
230                         DataColumn column = _table.Columns[columnIndex];
231                         _table.ChangingDataColumn (this, column, val);
232                                 
233                         if (original == null) original = new object [_table.Columns.Count];
234                         val = SetColumnValue (val, columnIndex);
235                         original[columnIndex] = val;
236                         rowState = DataRowState.Modified;
237                 }
238
239                 /// <summary>
240                 /// Gets or sets all of the values for this row through an array.
241                 /// </summary>
242                 public object[] ItemArray {
243                         get { 
244                                 // row not in table
245                                 if (rowState == DataRowState.Detached)
246                                         throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
247                                 // Accessing deleted rows
248                                 if (rowState == DataRowState.Deleted)
249                                         throw new DeletedRowInaccessibleException ("Deleted row information cannot be accessed through the row.");
250                                 
251                                 return current; 
252                         }
253                         set {
254                                 if (value.Length > _table.Columns.Count)
255                                         throw new ArgumentException ();
256
257                                 if (rowState == DataRowState.Deleted)
258                                         throw new DeletedRowInaccessibleException ();
259                                 
260                                 object[] newItems = new object[_table.Columns.Count];                   
261                                 object v = null;
262                                 for (int i = 0; i < _table.Columns.Count; i++) {
263
264                                         if (i < value.Length)
265                                                 v = value[i];
266                                         else
267                                                 v = null;
268
269                                         newItems[i] = SetColumnValue (v, i);
270                                 }
271
272                                 bool orginalEditing = editing;
273                                 if (!orginalEditing) BeginEdit ();
274                                 proposed = newItems;
275                                 if (!orginalEditing) EndEdit ();
276                         }
277                 }
278
279                 private object SetColumnValue (object v, int index) 
280                 {               
281                         object newval = null;
282                         DataColumn col = _table.Columns[index];
283                         
284                         if (_hasParentCollection && col.ReadOnly && v != this[index])
285                                 throw new ReadOnlyException ();
286
287                         if (v == null)
288                         {
289                                 if (col.DataType.ToString().Equals("System.Guid"))
290                                         throw new ArgumentException("Cannot set column to be null, Please use DBNull instead");
291
292                                 if(col.DefaultValue != DBNull.Value) 
293                                 {
294                                         newval = col.DefaultValue;
295                                 }
296                                 else if(col.AutoIncrement == true) 
297                                 {
298                                         newval = this [index];
299                                 }
300                                 else 
301                                 {
302                                         if (!col.AllowDBNull)
303                                         {
304                                                 //Constraint violations during data load is raise in DataTable EndLoad
305                                                 this._nullConstraintViolation = true;
306                                                 _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
307                                         }
308
309                                         newval = DBNull.Value;
310                                 }
311                         }               
312                         else if (v == DBNull.Value) 
313                         {
314                                 
315                                 if (!col.AllowDBNull)
316                                 {
317                                         //Constraint violations during data load is raise in DataTable EndLoad
318                                         this._nullConstraintViolation = true;
319                                         _nullConstraintMessage = "Column '" + col.ColumnName + "' does not allow nulls.";
320                                 }
321                                 
322                                 newval = DBNull.Value;
323                         }
324                         else 
325                         {       
326                                 Type vType = v.GetType(); // data type of value
327                                 Type cType = col.DataType; // column data type
328                                 if (cType != vType) 
329                                 {
330                                         TypeCode typeCode = Type.GetTypeCode(cType);
331                                         switch(typeCode) {
332                                                 case TypeCode.Boolean :
333                                                         v = Convert.ToBoolean (v);
334                                                         break;
335                                                 case TypeCode.Byte  :
336                                                         v = Convert.ToByte (v);
337                                                         break;
338                                                 case TypeCode.Char  :
339                                                         v = Convert.ToChar (v);
340                                                         break;
341                                                 case TypeCode.DateTime  :
342                                                         v = Convert.ToDateTime (v);
343                                                         break;
344                                                 case TypeCode.Decimal  :
345                                                         v = Convert.ToDecimal (v);
346                                                         break;
347                                                 case TypeCode.Double  :
348                                                         v = Convert.ToDouble (v);
349                                                         break;
350                                                 case TypeCode.Int16  :
351                                                         v = Convert.ToInt16 (v);
352                                                         break;
353                                                 case TypeCode.Int32  :
354                                                         v = Convert.ToInt32 (v);
355                                                         break;
356                                                 case TypeCode.Int64  :
357                                                         v = Convert.ToInt64 (v);
358                                                         break;
359                                                 case TypeCode.SByte  :
360                                                         v = Convert.ToSByte (v);
361                                                         break;
362                                                 case TypeCode.Single  :
363                                                         v = Convert.ToSingle (v);
364                                                         break;
365                                                 case TypeCode.String  :
366                                                         v = Convert.ToString (v);
367                                                         break;
368                                                 case TypeCode.UInt16  :
369                                                         v = Convert.ToUInt16 (v);
370                                                         break;
371                                                 case TypeCode.UInt32  :
372                                                         v = Convert.ToUInt32 (v);
373                                                         break;
374                                                 case TypeCode.UInt64  :
375                                                         v = Convert.ToUInt64 (v);
376                                                         break;
377                                                 default :
378                                                                 
379                                                 switch(cType.ToString()) {
380                                                         case "System.TimeSpan" :
381                                                                 v = (System.TimeSpan) v;
382                                                                 break;
383                                                         case "System.Type" :
384                                                                 v = (System.Type) v;
385                                                                 break;
386                                                         case "System.Object" :
387                                                                 //v = (System.Object) v;
388                                                                 break;
389                                                         default:
390                                                                 if (!cType.IsArray)
391                                                                         throw new InvalidCastException("Type not supported.");
392                                                                 break;
393                                                 }
394                                                         break;
395                                         }
396                                         vType = v.GetType();
397                                 }
398
399                                 // The MaxLength property is ignored for non-text columns
400                                 if ((Type.GetTypeCode(vType) == TypeCode.String) && (this.Table.Columns[index].MaxLength != -1) && 
401                                         (this.Table.Columns[index].MaxLength < ((string)v).Length)) {
402                                         throw new ArgumentException("Cannot set column '" + this.Table.Columns[index].ColumnName + "' to '" + v + "'. The value violates the MaxLength limit of this column.");
403                                 }
404                                 newval = v;
405                                 if(col.AutoIncrement == true) {
406                                         long inc = Convert.ToInt64(v);
407                                         col.UpdateAutoIncrementValue (inc);
408                                 }
409                         }
410                         col.DataHasBeenSet = true;
411                         return newval;
412                 }
413
414                 /// <summary>
415                 /// Gets or sets the custom error description for a row.
416                 /// </summary>
417                 public string RowError {
418                         get { return rowError; }
419                         set { rowError = value; }
420                 }
421
422                 /// <summary>
423                 /// Gets the current state of the row in regards to its relationship to the
424                 /// DataRowCollection.
425                 /// </summary>
426                 public DataRowState RowState {
427                         get { return rowState; }
428                 }
429
430                 //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
431                 //to a Datatable so I added this method. Delete if there is a better way.
432                 internal void AttachRow() {
433                         current = proposed;
434                         proposed = null;
435                         rowState = DataRowState.Added;
436                 }
437
438                 //FIXME?: Couldn't find a way to set the RowState when removing the DataRow
439                 //from a Datatable so I added this method. Delete if there is a better way.
440                 internal void DetachRow() {
441                         proposed = null;
442                         _rowId = -1;
443                         _hasParentCollection = false;
444                         rowState = DataRowState.Detached;
445                 }
446
447                 /// <summary>
448                 /// Gets the DataTable for which this row has a schema.
449                 /// </summary>
450                 public DataTable Table {
451                         get { return _table; }
452                 }
453
454                 /// <summary>
455                 /// Gets and sets index of row. This is used from 
456                 /// XmlDataDocument.
457                 // </summary>
458                 internal int XmlRowID {
459                         get { return xmlRowID; }
460                         set { xmlRowID = value; }
461                 }
462                 
463                 /// <summary>
464                 /// Gets and sets index of row.
465                 // </summary>
466                 internal int RowID {
467                         get { return _rowId; }
468                         set { _rowId = value; }
469                 }
470
471                 #endregion
472
473                 #region Methods
474
475                 /// <summary>
476                 /// Commits all the changes made to this row since the last time AcceptChanges was
477                 /// called.
478                 /// </summary>
479                 public void AcceptChanges () 
480                 {
481                         EndEdit(); // in case it hasn't been called
482                         switch (rowState) {
483                         case DataRowState.Added:
484                         case DataRowState.Modified:
485                                 rowState = DataRowState.Unchanged;
486                                 break;
487                         case DataRowState.Deleted:
488                                 _table.Rows.RemoveInternal (this);
489                                 DetachRow();
490                                 break;
491                         case DataRowState.Detached:
492                                 throw new RowNotInTableException("Cannot perform this operation on a row not in the table.");
493                         }
494                         // Accept from detached
495                         if (original == null)
496                                 original = new object[_table.Columns.Count];
497                         Array.Copy (current, original, _table.Columns.Count);
498                 }
499
500                 /// <summary>
501                 /// Begins an edit operation on a DataRow object.
502                 /// </summary>
503                 [MonoTODO]
504                 public void BeginEdit () 
505                 {
506                         if (rowState == DataRowState.Deleted)
507                                 throw new DeletedRowInaccessibleException ();
508                         if (!HasVersion (DataRowVersion.Proposed)) {
509                                 proposed = new object[_table.Columns.Count];
510                                 Array.Copy (current, proposed, current.Length);
511                         }
512                         //TODO: Suspend validation
513                         editing = true;
514                 }
515
516                 /// <summary>
517                 /// Cancels the current edit on the row.
518                 /// </summary>
519                 [MonoTODO]
520                 public void CancelEdit () 
521                 {
522                         editing = false;
523                         //TODO: Events
524                         if (HasVersion (DataRowVersion.Proposed)) {
525                                 proposed = null;
526                                 if (rowState == DataRowState.Modified)
527                                     rowState = DataRowState.Unchanged;
528                         }
529                 }
530
531                 /// <summary>
532                 /// Clears the errors for the row, including the RowError and errors set with
533                 /// SetColumnError.
534                 /// </summary>
535                 public void ClearErrors () 
536                 {
537                         rowError = String.Empty;
538                         columnErrors = new String[_table.Columns.Count];
539                 }
540
541                 /// <summary>
542                 /// Deletes the DataRow.
543                 /// </summary>
544                 [MonoTODO]
545                 public void Delete () 
546                 {
547                         _table.DeletingDataRow(this, DataRowAction.Delete);
548                         switch (rowState) {
549                         case DataRowState.Added:
550                                 // check what to do with child rows
551                                 CheckChildRows(DataRowAction.Delete);
552                                 _table.DeleteRowFromIndexes (this);
553                                 Table.Rows.RemoveInternal (this);
554
555                                 // if row was in Added state we move it to Detached.
556                                 DetachRow();
557                                 break;
558                         case DataRowState.Deleted:
559                                 break;
560                         default:
561                                 // check what to do with child rows
562                                 CheckChildRows(DataRowAction.Delete);
563                                 _table.DeleteRowFromIndexes (this);
564                                 rowState = DataRowState.Deleted;
565                                 break;
566                         }
567                         _table.DeletedDataRow(this, DataRowAction.Delete);
568                 }
569
570                 // check the child rows of this row before deleting the row.
571                 private void CheckChildRows(DataRowAction action)
572                 {
573                         
574                         // in this method we find the row that this row is in a relation with them.
575                         // in shortly we find all child rows of this row.
576                         // then we function according to the DeleteRule of the foriegnkey.
577
578
579                         // 1. find if this row is attached to dataset.
580                         // 2. find if EnforceConstraints is true.
581                         // 3. find if there are any constraint on the table that the row is in.
582                         if (_table.DataSet != null && _table.DataSet.EnforceConstraints && _table.Constraints.Count > 0)
583                         {
584                                 foreach (DataTable table in _table.DataSet.Tables)
585                                 {
586                                         // loop on all ForeignKeyConstrain of the table.
587                                         foreach (ForeignKeyConstraint fk in table.Constraints.ForeignKeyConstraints)
588                                         {
589                                                 if (fk.RelatedTable == _table)
590                                                 {
591                                                         Rule rule;
592                                                         if (action == DataRowAction.Delete)
593                                                                 rule = fk.DeleteRule;
594                                                         else
595                                                                 rule = fk.UpdateRule;
596                                                         CheckChildRows(fk, action, rule);
597                                                 }                       
598                                         }
599                                 }
600                         }
601                 }
602
603                 private void CheckChildRows(ForeignKeyConstraint fkc, DataRowAction action, Rule rule)
604                 {                               
605                         DataRow[] childRows = GetChildRows(fkc, DataRowVersion.Default);
606                         switch (rule)
607                         {
608                                 case Rule.Cascade:  // delete or change all relted rows.
609                                         if (childRows != null)
610                                         {
611                                                 for (int j = 0; j < childRows.Length; j++)
612                                                 {
613                                                         // if action is delete we delete all child rows
614                                                         if (action == DataRowAction.Delete)
615                                                         {
616                                                                 if (childRows[j].RowState != DataRowState.Deleted)
617                                                                         childRows[j].Delete();
618                                                         }
619                                                         // if action is change we change the values in the child row
620                                                         else if (action == DataRowAction.Change)
621                                                         {
622                                                                 // change only the values in the key columns
623                                                                 // set the childcolumn value to the new parent row value
624                                                                 for (int k = 0; k < fkc.Columns.Length; k++)
625                                                                         childRows[j][fkc.Columns[k]] = this[fkc.RelatedColumns[k], DataRowVersion.Proposed];
626                                                         }
627                                                 }
628                                         }
629                                         break;
630                                 case Rule.None: // throw an exception if there are any child rows.
631                                         if (childRows != null)
632                                         {
633                                                 for (int j = 0; j < childRows.Length; j++)
634                                                 {
635                                                         if (childRows[j].RowState != DataRowState.Deleted)
636                                                         {
637                                                                 string changeStr = "Cannot change this row because constraints are enforced on relation " + fkc.ConstraintName +", and changing this row will strand child rows.";
638                                                                 string delStr = "Cannot delete this row because constraints are enforced on relation " + fkc.ConstraintName +", and deleting this row will strand child rows.";
639                                                                 string message = action == DataRowAction.Delete ? delStr : changeStr;
640                                                                 throw new InvalidConstraintException(message);
641                                                         }
642                                                 }
643                                         }
644                                         break;
645                                 case Rule.SetDefault: // set the values in the child rows to the defult value of the columns.
646                                         if (childRows != null)
647                                         {
648                                                 for (int j = 0; j < childRows.Length; j++)
649                                                 {
650                                                         DataRow child = childRows[j];
651                                                         if (childRows[j].RowState != DataRowState.Deleted)
652                                                         {
653                                                                 //set only the key columns to default
654                                                                 for (int k = 0; k < fkc.Columns.Length; k++)
655                                                                         child[fkc.Columns[k]] = fkc.Columns[k].DefaultValue;
656                                                         }
657                                                 }
658                                         }
659                                         break;
660                                 case Rule.SetNull: // set the values in the child row to null.
661                                         if (childRows != null)
662                                         {
663                                                 for (int j = 0; j < childRows.Length; j++)
664                                                 {
665                                                         DataRow child = childRows[j];
666                                                         if (childRows[j].RowState != DataRowState.Deleted)
667                                                         {
668                                                                 // set only the key columns to DBNull
669                                                                 for (int k = 0; k < fkc.Columns.Length; k++)
670                                                                         child.SetNull(fkc.Columns[k]);
671                                                         }
672                                                 }
673                                         }
674                                         break;
675                         }
676
677                 }
678
679                 /// <summary>
680                 /// Ends the edit occurring on the row.
681                 /// </summary>
682                 [MonoTODO]
683                 public void EndEdit () 
684                 {
685                         if (_inChangingEvent)
686                                 throw new InRowChangingEventException("Cannot call EndEdit inside an OnRowChanging event.");
687                         if (rowState == DataRowState.Detached)
688                         {
689                                 editing = false;
690                                 return;
691                         }
692
693                         if (HasVersion (DataRowVersion.Proposed))
694                         {
695                                 _inChangingEvent = true;
696                                 try
697                                 {
698                                         _table.ChangingDataRow(this, DataRowAction.Change);
699                                 }
700                                 finally
701                                 {
702                                         _inChangingEvent = false;
703                                 }
704                                 if (rowState == DataRowState.Unchanged)
705                                         rowState = DataRowState.Modified;
706                                 
707                                 //Calling next method validates UniqueConstraints
708                                 //and ForeignKeys.
709                                 try
710                                 {
711                                         if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
712                                                 _table.Rows.ValidateDataRowInternal(this);
713                                 }
714                                 catch (Exception e)
715                                 {
716                                         editing = false;
717                                         proposed = null;
718                                         throw e;
719                                 }
720
721                                 // Now we are going to check all child rows of current row.
722                                 // In the case the cascade is true the child rows will look up for
723                                 // parent row. since lookup in index is always on current,
724                                 // we have to move proposed version of current row to current
725                                 // in the case of check child row failure we are rolling 
726                                 // current row state back.
727                                 object[] backup = current;
728                                 current = proposed;
729                                 proposed = null;
730                                 bool editing_backup = editing;
731                                 editing = false;
732                                 try {
733                                         // check all child rows.
734                                         CheckChildRows(DataRowAction.Change);
735                                 }
736                                 catch (Exception ex) {
737                                         // if check child rows failed - rollback to previous state
738                                         // i.e. restore proposed and current versions
739                                         proposed = current;
740                                         current = backup;
741                                         editing = editing_backup;
742                                         // since we failed - propagate an exception
743                                         throw ex;
744                                 }
745                                 _table.ChangedDataRow(this, DataRowAction.Change);
746                         }
747                 }
748
749                 /// <summary>
750                 /// Gets the child rows of this DataRow using the specified DataRelation.
751                 /// </summary>
752                 public DataRow[] GetChildRows (DataRelation relation) 
753                 {
754                         return GetChildRows (relation, DataRowVersion.Current);
755                 }
756
757                 /// <summary>
758                 /// Gets the child rows of a DataRow using the specified RelationName of a
759                 /// DataRelation.
760                 /// </summary>
761                 public DataRow[] GetChildRows (string relationName) 
762                 {
763                         return GetChildRows (Table.DataSet.Relations[relationName]);
764                 }
765
766                 /// <summary>
767                 /// Gets the child rows of a DataRow using the specified DataRelation, and
768                 /// DataRowVersion.
769                 /// </summary>
770                 public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version) 
771                 {
772                         if (relation == null)
773                                 return new DataRow[0];
774
775                         if (this.Table == null || RowState == DataRowState.Detached)
776                                 throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
777
778                         if (relation.DataSet != this.Table.DataSet)
779                                 throw new ArgumentException();
780
781                         if (relation.ChildKeyConstraint != null)
782                                 return GetChildRows (relation.ChildKeyConstraint, version);
783
784                         ArrayList rows = new ArrayList();
785                         DataColumn[] parentColumns = relation.ParentColumns;
786                         DataColumn[] childColumns = relation.ChildColumns;
787                         int numColumn = parentColumns.Length;
788                         if (HasVersion(version))
789                         {
790                                 object[] vals = new object[parentColumns.Length];
791                                 for (int i = 0; i < vals.Length; i++)
792                                         vals[i] = this[parentColumns[i], version];
793                                 
794                                 foreach (DataRow row in relation.ChildTable.Rows) 
795                                 {
796                                         bool allColumnsMatch = false;
797                                         if (row.HasVersion(DataRowVersion.Default))
798                                         {
799                                                 allColumnsMatch = true;
800                                                 for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) 
801                                                 {
802                                                         if (!vals[columnCnt].Equals(
803                                                                 row[childColumns[columnCnt], DataRowVersion.Default])) 
804                                                         {
805                                                                 allColumnsMatch = false;
806                                                                 break;
807                                                         }
808                                                 }
809                                         }
810                                         if (allColumnsMatch) rows.Add(row);
811                                 }
812                         }
813                         DataRow[] result = relation.ChildTable.NewRowArray(rows.Count);
814                         rows.CopyTo(result, 0);
815                         return result;
816                 }
817
818                 /// <summary>
819                 /// Gets the child rows of a DataRow using the specified RelationName of a
820                 /// DataRelation, and DataRowVersion.
821                 /// </summary>
822                 public DataRow[] GetChildRows (string relationName, DataRowVersion version) 
823                 {
824                         return GetChildRows (Table.DataSet.Relations[relationName], version);
825                 }
826
827                 private DataRow[] GetChildRows (ForeignKeyConstraint fkc, DataRowVersion version) 
828                 {
829                         ArrayList rows = new ArrayList();
830                         DataColumn[] parentColumns = fkc.RelatedColumns;
831                         DataColumn[] childColumns = fkc.Columns;
832                         int numColumn = parentColumns.Length;
833                         if (HasVersion(version))
834                         {
835                                 object[] vals = new object[parentColumns.Length];
836                                 for (int i = 0; i < vals.Length; i++)
837                                         vals[i] = this[parentColumns[i], version];
838
839                                 Index index = fkc.Index;
840                                 if (index != null) {
841                                         // get the child rows from the index
842                                         Node[] childNodes = index.FindAllSimple (vals);
843                                         for (int i = 0; i < childNodes.Length; i++) {
844                                                 rows.Add (childNodes[i].Row);
845                                         }
846                                 }
847                                 else { // if there is no index we search manualy.
848                                         foreach (DataRow row in fkc.Table.Rows) 
849                                         {
850                                                 bool allColumnsMatch = false;
851                                                 if (row.HasVersion(DataRowVersion.Default))
852                                                 {
853                                                         allColumnsMatch = true;
854                                                         for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) 
855                                                         {
856                                                                 if (!vals[columnCnt].Equals(
857                                                                         row[childColumns[columnCnt], DataRowVersion.Default])) 
858                                                                 {
859                                                                         allColumnsMatch = false;
860                                                                         break;
861                                                                 }
862                                                         }
863                                                 }
864                                                 if (allColumnsMatch) rows.Add(row);
865                                         }
866                                 }
867                         }
868
869                         DataRow[] result = fkc.Table.NewRowArray(rows.Count);
870                         rows.CopyTo(result, 0);
871                         return result;
872                 }
873
874                 /// <summary>
875                 /// Gets the error description of the specified DataColumn.
876                 /// </summary>
877                 public string GetColumnError (DataColumn column) 
878                 {
879                         return GetColumnError (_table.Columns.IndexOf(column));
880                 }
881
882                 /// <summary>
883                 /// Gets the error description for the column specified by index.
884                 /// </summary>
885                 public string GetColumnError (int columnIndex) 
886                 {
887                         if (columnIndex < 0 || columnIndex >= columnErrors.Length)
888                                 throw new IndexOutOfRangeException ();
889
890                         string retVal = columnErrors[columnIndex];
891                         if (retVal == null)
892                                 retVal = string.Empty;
893                         return retVal;
894                 }
895
896                 /// <summary>
897                 /// Gets the error description for the column, specified by name.
898                 /// </summary>
899                 public string GetColumnError (string columnName) 
900                 {
901                         return GetColumnError (_table.Columns.IndexOf(columnName));
902                 }
903
904                 /// <summary>
905                 /// Gets an array of columns that have errors.
906                 /// </summary>
907                 public DataColumn[] GetColumnsInError () 
908                 {
909                         ArrayList dataColumns = new ArrayList ();
910
911                         for (int i = 0; i < columnErrors.Length; i += 1)
912                         {
913                                 if (columnErrors[i] != null && columnErrors[i] != String.Empty)
914                                         dataColumns.Add (_table.Columns[i]);
915                         }
916
917                         return (DataColumn[])(dataColumns.ToArray (typeof(DataColumn)));
918                 }
919
920                 /// <summary>
921                 /// Gets the parent row of a DataRow using the specified DataRelation.
922                 /// </summary>
923                 public DataRow GetParentRow (DataRelation relation) 
924                 {
925                         return GetParentRow (relation, DataRowVersion.Current);
926                 }
927
928                 /// <summary>
929                 /// Gets the parent row of a DataRow using the specified RelationName of a
930                 /// DataRelation.
931                 /// </summary>
932                 public DataRow GetParentRow (string relationName) 
933                 {
934                         return GetParentRow (relationName, DataRowVersion.Current);
935                 }
936
937                 /// <summary>
938                 /// Gets the parent row of a DataRow using the specified DataRelation, and
939                 /// DataRowVersion.
940                 /// </summary>
941                 public DataRow GetParentRow (DataRelation relation, DataRowVersion version) 
942                 {
943                         DataRow[] rows = GetParentRows(relation, version);
944                         if (rows.Length == 0) return null;
945                         return rows[0];
946                 }
947
948                 /// <summary>
949                 /// Gets the parent row of a DataRow using the specified RelationName of a 
950                 /// DataRelation, and DataRowVersion.
951                 /// </summary>
952                 public DataRow GetParentRow (string relationName, DataRowVersion version) 
953                 {
954                         return GetParentRow (Table.DataSet.Relations[relationName], version);
955                 }
956
957                 /// <summary>
958                 /// Gets the parent rows of a DataRow using the specified DataRelation.
959                 /// </summary>
960                 public DataRow[] GetParentRows (DataRelation relation) 
961                 {
962                         return GetParentRows (relation, DataRowVersion.Current);
963                 }
964
965                 /// <summary>
966                 /// Gets the parent rows of a DataRow using the specified RelationName of a 
967                 /// DataRelation.
968                 /// </summary>
969                 public DataRow[] GetParentRows (string relationName) 
970                 {
971                         return GetParentRows (relationName, DataRowVersion.Current);
972                 }
973
974                 /// <summary>
975                 /// Gets the parent rows of a DataRow using the specified DataRelation, and
976                 /// DataRowVersion.
977                 /// </summary>
978                 public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version) 
979                 {
980                         // TODO: Caching for better preformance
981                         if (relation == null)
982                                 return new DataRow[0];
983
984                         if (this.Table == null || RowState == DataRowState.Detached)
985                                 throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
986
987                         if (relation.DataSet != this.Table.DataSet)
988                                 throw new ArgumentException();
989
990                         ArrayList rows = new ArrayList();
991                         DataColumn[] parentColumns = relation.ParentColumns;
992                         DataColumn[] childColumns = relation.ChildColumns;
993                         int numColumn = parentColumns.Length;
994                         if (HasVersion(version))
995                         {
996                                 object[] vals = new object[childColumns.Length];
997                                 for (int i = 0; i < vals.Length; i++)
998                                         vals[i] = this[childColumns[i], version];
999                                 
1000                                 Index indx = relation.ParentTable.GetIndexByColumns (parentColumns);
1001                                 if (indx != null) { // get the child rows from the index
1002                                         Node[] childNodes = indx.FindAllSimple (vals);
1003                                         for (int i = 0; i < childNodes.Length; i++) {
1004                                                 rows.Add (childNodes[i].Row);
1005                                         }
1006                                 }
1007                                 else { // no index so we have to search manualy.
1008                                         foreach (DataRow row in relation.ParentTable.Rows) 
1009                                         {
1010                                                 bool allColumnsMatch = false;
1011                                                 if (row.HasVersion(DataRowVersion.Default))
1012                                                 {
1013                                                         allColumnsMatch = true;
1014                                                         for (int columnCnt = 0; columnCnt < numColumn; columnCnt++) 
1015                                                         {
1016                                                                 if (!this[childColumns[columnCnt], version].Equals(
1017                                                                         row[parentColumns[columnCnt], DataRowVersion.Default])) 
1018                                                                 {
1019                                                                         allColumnsMatch = false;
1020                                                                         break;
1021                                                                 }
1022                                                         }
1023                                                 }
1024                                                 if (allColumnsMatch) rows.Add(row);
1025                                         }
1026                                 }
1027                         }
1028
1029                         DataRow[] result = relation.ParentTable.NewRowArray(rows.Count);
1030                         rows.CopyTo(result, 0);
1031                         return result;
1032                 }
1033
1034                 /// <summary>
1035                 /// Gets the parent rows of a DataRow using the specified RelationName of a 
1036                 /// DataRelation, and DataRowVersion.
1037                 /// </summary>
1038                 public DataRow[] GetParentRows (string relationName, DataRowVersion version) 
1039                 {
1040                         return GetParentRows (Table.DataSet.Relations[relationName], version);
1041                 }
1042
1043                 /// <summary>
1044                 /// Gets a value indicating whether a specified version exists.
1045                 /// </summary>
1046                 public bool HasVersion (DataRowVersion version) 
1047                 {
1048                         switch (version)
1049                         {
1050                                 case DataRowVersion.Default:
1051                                         if (rowState == DataRowState.Deleted)
1052                                                 return false;
1053                                         if (rowState == DataRowState.Detached)
1054                                                 return proposed != null;
1055                                         return true;
1056                                 case DataRowVersion.Proposed:
1057                                         if (rowState == DataRowState.Deleted)
1058                                                 return false;
1059                                         return (proposed != null);
1060                                 case DataRowVersion.Current:
1061                                         if (rowState == DataRowState.Deleted || rowState == DataRowState.Detached)
1062                                                 return false;
1063                                         return (current != null);
1064                                 case DataRowVersion.Original:
1065                                         if (rowState == DataRowState.Detached)
1066                                                 return false;
1067                                         return (original != null);
1068                         }
1069                         return false;
1070                 }
1071
1072                 /// <summary>
1073                 /// Gets a value indicating whether the specified DataColumn contains a null value.
1074                 /// </summary>
1075                 public bool IsNull (DataColumn column) 
1076                 {
1077                         object o = this[column];
1078                         return (o == DBNull.Value);
1079                 }
1080
1081                 /// <summary>
1082                 /// Gets a value indicating whether the column at the specified index contains a null
1083                 /// value.
1084                 /// </summary>
1085                 public bool IsNull (int columnIndex) 
1086                 {
1087                         object o = this[columnIndex];
1088                         return (o == DBNull.Value);
1089                 }
1090
1091                 /// <summary>
1092                 /// Gets a value indicating whether the named column contains a null value.
1093                 /// </summary>
1094                 public bool IsNull (string columnName) 
1095                 {
1096                         object o = this[columnName];
1097                         return (o == DBNull.Value);
1098                 }
1099
1100                 /// <summary>
1101                 /// Gets a value indicating whether the specified DataColumn and DataRowVersion
1102                 /// contains a null value.
1103                 /// </summary>
1104                 public bool IsNull (DataColumn column, DataRowVersion version) 
1105                 {
1106                         object o = this[column, version];
1107                         return (o == DBNull.Value);
1108                 }
1109
1110                 /// <summary>
1111                 /// Returns a value indicating whether all of the row columns specified contain a null value.
1112                 /// </summary>
1113                 internal bool IsNullColumns(DataColumn[] columns)
1114                 {
1115                         bool allNull = true;
1116                         for (int i = 0; i < columns.Length; i++) 
1117                         {
1118                                 if (!IsNull(columns[i])) 
1119                                 {
1120                                         allNull = false;
1121                                         break;
1122                                 }
1123                         }
1124                         return allNull;
1125                 }
1126
1127                 /// <summary>
1128                 /// Rejects all changes made to the row since AcceptChanges was last called.
1129                 /// </summary>
1130                 public void RejectChanges () 
1131                 {
1132                         if (RowState == DataRowState.Detached)
1133                                 throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
1134                         // If original is null, then nothing has happened since AcceptChanges
1135                         // was last called.  We have no "original" to go back to.
1136                         if (original != null)
1137                         {
1138                                 Array.Copy (original, current, _table.Columns.Count);
1139                                
1140                                 _table.ChangedDataRow (this, DataRowAction.Rollback);
1141                                 CancelEdit ();
1142                                 switch (rowState)
1143                                 {
1144                                         case DataRowState.Added:
1145                                                 _table.DeleteRowFromIndexes (this);
1146                                                 _table.Rows.RemoveInternal (this);
1147                                                 break;
1148                                         case DataRowState.Modified:
1149                                                 if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
1150                                                         _table.Rows.ValidateDataRowInternal(this);
1151                                                 rowState = DataRowState.Unchanged;
1152                                                 break;
1153                                         case DataRowState.Deleted:
1154                                                 rowState = DataRowState.Unchanged;
1155                                                 if ((_table.DataSet == null || _table.DataSet.EnforceConstraints) && !_table._duringDataLoad)
1156                                                         _table.Rows.ValidateDataRowInternal(this);
1157                                                 break;
1158                                 } 
1159                                 
1160                         }                       
1161                         else {
1162                                 // If rows are just loaded via Xml the original values are null.
1163                                 // So in this case we have to remove all columns.
1164                                 // FIXME: I'm not realy sure, does this break something else, but
1165                                 // if so: FIXME ;)
1166                                 
1167                                 if ((rowState & DataRowState.Added) > 0)
1168                                 {
1169                                         _table.DeleteRowFromIndexes (this);
1170                                         _table.Rows.RemoveInternal (this);
1171                                         // if row was in Added state we move it to Detached.
1172                                         DetachRow();
1173                                 }
1174                         }
1175                 }
1176
1177                 /// <summary>
1178                 /// Sets the error description for a column specified as a DataColumn.
1179                 /// </summary>
1180                 public void SetColumnError (DataColumn column, string error) 
1181                 {
1182                         SetColumnError (_table.Columns.IndexOf (column), error);
1183                 }
1184
1185                 /// <summary>
1186                 /// Sets the error description for a column specified by index.
1187                 /// </summary>
1188                 public void SetColumnError (int columnIndex, string error) 
1189                 {
1190                         if (columnIndex < 0 || columnIndex >= columnErrors.Length)
1191                                 throw new IndexOutOfRangeException ();
1192                         columnErrors[columnIndex] = error;
1193                 }
1194
1195                 /// <summary>
1196                 /// Sets the error description for a column specified by name.
1197                 /// </summary>
1198                 public void SetColumnError (string columnName, string error) 
1199                 {
1200                         SetColumnError (_table.Columns.IndexOf (columnName), error);
1201                 }
1202
1203                 /// <summary>
1204                 /// Sets the value of the specified DataColumn to a null value.
1205                 /// </summary>
1206                 protected void SetNull (DataColumn column) 
1207                 {
1208                         this[column] = DBNull.Value;
1209                 }
1210
1211                 /// <summary>
1212                 /// Sets the parent row of a DataRow with specified new parent DataRow.
1213                 /// </summary>
1214                 public void SetParentRow (DataRow parentRow) 
1215                 {
1216                         SetParentRow(parentRow, null);
1217                 }
1218
1219                 /// <summary>
1220                 /// Sets the parent row of a DataRow with specified new parent DataRow and
1221                 /// DataRelation.
1222                 /// </summary>
1223                 public void SetParentRow (DataRow parentRow, DataRelation relation) 
1224                 {
1225                         if (_table == null || parentRow.Table == null || RowState == DataRowState.Detached)
1226                                 throw new RowNotInTableException("This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.");
1227
1228                         if (parentRow != null && _table.DataSet != parentRow.Table.DataSet)
1229                                 throw new ArgumentException();
1230                         
1231                         BeginEdit();
1232                         if (relation == null)
1233                         {
1234                                 foreach (DataRelation parentRel in _table.ParentRelations)
1235                                 {
1236                                         DataColumn[] childCols = parentRel.ChildKeyConstraint.Columns;
1237                                         DataColumn[] parentCols = parentRel.ChildKeyConstraint.RelatedColumns;
1238                                         
1239                                         for (int i = 0; i < parentCols.Length; i++)
1240                                         {
1241                                                 if (parentRow == null)
1242                                                         this[childCols[i].Ordinal] = DBNull.Value;
1243                                                 else
1244                                                         this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1245                                         }
1246                                         
1247                                 }
1248                         }
1249                         else
1250                         {
1251                                 DataColumn[] childCols = relation.ChildKeyConstraint.Columns;
1252                                 DataColumn[] parentCols = relation.ChildKeyConstraint.RelatedColumns;
1253                                         
1254                                 for (int i = 0; i < parentCols.Length; i++)
1255                                 {
1256                                         if (parentRow == null)
1257                                                 this[childCols[i].Ordinal] = DBNull.Value;
1258                                         else
1259                                                 this[childCols[i].Ordinal] = parentRow[parentCols[i]];
1260                                 }
1261                         }
1262                         EndEdit();
1263                 }
1264                 
1265                 //Copy all values of this DataaRow to the row parameter.
1266                 internal void CopyValuesToRow(DataRow row)
1267                 {
1268                                                 
1269                         if (row == null)
1270                                 throw new ArgumentNullException("row");
1271                         if (row == this)
1272                                 throw new ArgumentException("'row' is the same as this object");
1273
1274                         DataColumnCollection columns = Table.Columns;
1275                         
1276                         for(int i = 0; i < columns.Count; i++){
1277
1278                                 string columnName = columns[i].ColumnName;
1279                                 int index = row.Table.Columns.IndexOf(columnName);
1280                                 //if a column with the same name exists in both rows copy the values
1281                                 if(index != -1) {
1282                                         if (HasVersion(DataRowVersion.Original))
1283                                         {
1284                                                 if (row.original == null)
1285                                                         row.original = new object[row.Table.Columns.Count];
1286                                                 row.original[index] = row.SetColumnValue(original[i], index);
1287                                         }
1288                                         if (HasVersion(DataRowVersion.Current))
1289                                         {
1290                                                 if (row.current == null)
1291                                                         row.current = new object[row.Table.Columns.Count];
1292                                                 row.current[index] = row.SetColumnValue(current[i], index);
1293                                         }
1294                                         if (HasVersion(DataRowVersion.Proposed))
1295                                         {
1296                                                 if (row.proposed == null)
1297                                                         row.proposed = new object[row.Table.Columns.Count];
1298                                                 row.proposed[index] = row.SetColumnValue(proposed[i], index);
1299                                         }
1300                                         
1301                                         //Saving the current value as the column value
1302                                         row[index] = row.current[index];
1303                                         
1304                                 }
1305                         }
1306
1307                         row.rowState = RowState;
1308                         row.RowError = RowError;
1309                         row.columnErrors = columnErrors;
1310                 }
1311
1312                 
1313                 public void CollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs args)
1314                 {
1315                         // if a column is added we hava to add an additional value the 
1316                         // the priginal, current and propoed arrays.
1317                         // this scenario can happened in merge operation.
1318
1319                         if (args.Action == System.ComponentModel.CollectionChangeAction.Add)
1320                         {
1321                                 object[] tmp;
1322                                 if (current != null)
1323                                 {
1324                                         tmp = new object[current.Length + 1];
1325                                         Array.Copy (current, tmp, current.Length);
1326                                         tmp[tmp.Length - 1] = SetColumnValue(null, tmp.Length - 1);
1327                                         current = tmp;
1328                                 }
1329                                 if (proposed != null)
1330                                 {
1331                                         tmp = new object[proposed.Length + 1];
1332                                         Array.Copy (proposed, tmp, proposed.Length);
1333                                         tmp[tmp.Length - 1] = SetColumnValue(null, tmp.Length - 1);
1334                                         proposed = tmp;
1335                                 }
1336                                 if(original != null)
1337                                 {
1338                                         tmp = new object[original.Length + 1];
1339                                         Array.Copy (original, tmp, original.Length);
1340                                         tmp[tmp.Length - 1] = SetColumnValue(null, tmp.Length - 1);
1341                                         original = tmp;
1342                                 }
1343
1344                         }
1345                 }
1346
1347                 internal bool IsRowChanged(DataRowState rowState) {
1348                         if((RowState & rowState) != 0)
1349                                 return true;
1350
1351                         //we need to find if child rows of this row changed.
1352                         //if yes - we should return true
1353
1354                         // if the rowState is deleted we should get the original version of the row
1355                         // else - we should get the current version of the row.
1356                         DataRowVersion version = (rowState == DataRowState.Deleted) ? DataRowVersion.Original : DataRowVersion.Current;
1357                         int count = Table.ChildRelations.Count;
1358                         for (int i = 0; i < count; i++){
1359                                 DataRelation rel = Table.ChildRelations[i];
1360                                 DataRow[] childRows = GetChildRows(rel, version);
1361                                 for (int j = 0; j < childRows.Length; j++){
1362                                         if (childRows[j].IsRowChanged(rowState))
1363                                                 return true;
1364                                 }
1365                         }
1366
1367                         return false;
1368                 }
1369
1370                 internal bool HasParentCollection
1371                 {
1372                         get
1373                         {
1374                                 return _hasParentCollection;
1375                         }
1376                         set
1377                         {
1378                                 _hasParentCollection = value;
1379                         }
1380                 }
1381
1382                 internal void CheckNullConstraints()
1383                 {
1384                         if (_nullConstraintViolation)
1385                         {
1386                                 for (int i = 0; i < proposed.Length; i++)
1387                                 {
1388                                         if (this[i] == DBNull.Value && !_table.Columns[i].AllowDBNull)
1389                                                 throw new NoNullAllowedException(_nullConstraintMessage);
1390                                 }
1391                                 _nullConstraintViolation = false;
1392                         }
1393                 }
1394
1395                 #endregion // Methods
1396         }
1397
1398         
1399
1400 }