2 // System.Data.DataRow.cs
5 // Rodrigo Moya <rodrigo@ximian.com>
6 // Daniel Morgan <danmorg@sc.rr.com>
7 // Tim Coleman <tim@timcoleman.com>
9 // (C) Ximian, Inc 2002
10 // (C) Daniel Morgan 2002
11 // Copyright (C) 2002 Tim Coleman
15 using System.Collections;
17 namespace System.Data {
19 /// Represents a row of data in a DataTable.
26 private DataTable _table;
28 private object[] original;
29 private object[] proposed;
30 private object[] current;
32 private string[] columnErrors;
33 private string rowError;
34 private DataRowState rowState;
35 internal int xmlRowID = 0;
42 /// This member supports the .NET Framework infrastructure and is not intended to be
43 /// used directly from your code.
45 protected internal DataRow (DataRowBuilder builder)
47 _table = builder.Table;
51 current = new object[_table.Columns.Count];
53 columnErrors = new string[_table.Columns.Count];
54 rowError = String.Empty;
56 //rowState = DataRowState.Unchanged;
58 //on first creating a DataRow it is always detached.
59 rowState = DataRowState.Detached;
67 /// Gets a value indicating whether there are errors in a row.
69 public bool HasErrors {
72 throw new NotImplementedException ();
77 /// Gets or sets the data stored in the column specified by name.
79 public object this[string columnName] {
80 [MonoTODO] //FIXME: will return different values depending on DataRowState
81 get { return this[columnName, DataRowVersion.Current]; }
84 DataColumn column = _table.Columns[columnName];
86 throw new IndexOutOfRangeException ();
92 /// Gets or sets the data stored in specified DataColumn
94 public object this[DataColumn column] {
95 [MonoTODO] //FIXME: will return different values depending on DataRowState
96 get { return this[column, DataRowVersion.Current]; }
100 value = (value == null) ? DBNull.Value : value;
\r
101 bool objIsDBNull = value.Equals(DBNull.Value);
103 throw new ArgumentNullException ();
104 int columnIndex = _table.Columns.IndexOf (column);
105 if (columnIndex == -1)
106 throw new ArgumentException ();
107 if(column.DataType != value.GetType ()) {
108 if(objIsDBNull == true && column.AllowDBNull == false)
109 throw new InvalidCastException ();
110 //else if(objIsDBNull == false)
111 // throw new InvalidCastException ();
114 if (rowState == DataRowState.Deleted)
115 throw new DeletedRowInaccessibleException ();
117 //MS Implementation doesn't seem to create the proposed or original
118 //set of values when a datarow has just been created or added to the
119 //DataTable and AcceptChanges() has not been called yet.
121 if(rowState == DataRowState.Detached || rowState == DataRowState.Added) {
123 current[columnIndex] = DBNull.Value;
125 current[columnIndex] = value;
126 _table.ChangedDataColumn (this, column, value);
129 BeginEdit (); // implicitly called
131 rowState = DataRowState.Modified;
134 proposed[columnIndex] = DBNull.Value;
136 proposed[columnIndex] = value;
137 _table.ChangedDataColumn (this, column, value);
140 //Don't know if this is the rigth thing to do,
141 //but it fixes my test. I believe the MS docs only say this
142 //method is implicitly called when calling AcceptChanges()
144 // EndEdit (); // is this the right thing to do?
150 /// Gets or sets the data stored in column specified by index.
152 public object this[int columnIndex] {
153 [MonoTODO] //FIXME: not always supposed to return current
154 get { return this[columnIndex, DataRowVersion.Current]; }
157 DataColumn column = _table.Columns[columnIndex]; //FIXME: will throw
159 throw new IndexOutOfRangeException ();
160 this[column] = value;
165 /// Gets the specified version of data stored in the named column.
167 public object this[string columnName, DataRowVersion version] {
170 DataColumn column = _table.Columns[columnName]; //FIXME: will throw
172 throw new IndexOutOfRangeException ();
173 return this[column, version];
178 /// Gets the specified version of data stored in the specified DataColumn.
180 public object this[DataColumn column, DataRowVersion version] {
183 throw new ArgumentNullException ();
185 int columnIndex = _table.Columns.IndexOf (column);
187 if (columnIndex == -1)
188 throw new ArgumentException ();
190 if (version == DataRowVersion.Default)
191 return column.DefaultValue;
193 if (!HasVersion (version))
194 throw new VersionNotFoundException ();
198 case DataRowVersion.Proposed:
199 return proposed[columnIndex];
200 case DataRowVersion.Current:
201 return current[columnIndex];
202 case DataRowVersion.Original:
203 return original[columnIndex];
205 throw new ArgumentException ();
211 /// Gets the data stored in the column, specified by index and version of the data to
214 public object this[int columnIndex, DataRowVersion version] {
217 DataColumn column = _table.Columns[columnIndex]; //FIXME: throws
219 throw new IndexOutOfRangeException ();
220 return this[column, version];
225 /// Gets or sets all of the values for this row through an array.
228 public object[] ItemArray {
229 get { return current; }
231 if (value.Length > _table.Columns.Count)
232 throw new ArgumentException ();
234 if (rowState == DataRowState.Deleted)
235 throw new DeletedRowInaccessibleException ();
237 for (int i = 0; i < value.Length; i += 1)
239 if (_table.Columns[i].ReadOnly && value[i] != this[i])
240 throw new ReadOnlyException ();
242 if (value[i] == null)
244 if (!_table.Columns[i].AllowDBNull)
245 throw new NoNullAllowedException ();
249 //FIXME: int strings can be converted to ints
250 if (_table.Columns[i].DataType != value[i].GetType())
251 throw new InvalidCastException ();
254 //FIXME: BeginEdit() not correct
255 BeginEdit (); // implicitly called
256 rowState = DataRowState.Modified;
258 //FIXME: this isn't correct. a shorter array can set the first few values
259 //and not touch the rest. So not all the values will get replaced
265 /// Gets or sets the custom error description for a row.
267 public string RowError {
268 get { return rowError; }
269 set { rowError = value; }
273 /// Gets the current state of the row in regards to its relationship to the
274 /// DataRowCollection.
276 public DataRowState RowState {
277 get { return rowState; }
280 //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
281 //to a Datatable so I added this method. Delete if there is a better way.
282 internal DataRowState RowStateInternal {
283 set { rowState = value;}
287 /// Gets the DataTable for which this row has a schema.
289 public DataTable Table {
290 get { return _table; }
294 /// Gets and sets index of row. This is used from
297 internal int XmlRowID {
298 get { return xmlRowID; }
299 set { xmlRowID = value; }
307 /// Commits all the changes made to this row since the last time AcceptChanges was
311 public void AcceptChanges ()
314 if(rowState == DataRowState.Added)
316 //Instantiate original and proposed values so that we can call
325 case DataRowState.Added:
326 case DataRowState.Detached:
327 case DataRowState.Modified:
328 rowState = DataRowState.Unchanged;
330 case DataRowState.Deleted:
331 _table.Rows.Remove (this); //FIXME: this should occur in end edit
335 //MS implementation assigns the Proposed values
336 //to both current and original and keeps original after calling AcceptChanges
337 //Copy proposed to original in this.EndEdit()
342 /// Begins an edit operation on a DataRow object.
345 public void BeginEdit()
347 if (rowState == DataRowState.Deleted)
348 throw new DeletedRowInaccessibleException ();
350 if (!HasVersion (DataRowVersion.Proposed))
352 proposed = new object[_table.Columns.Count];
353 Array.Copy (current, proposed, _table.Columns.Count);
355 //TODO: Suspend validation
357 //FIXME: this doesn't happen on begin edit
358 if (!HasVersion (DataRowVersion.Original))
360 original = new object[_table.Columns.Count];
361 Array.Copy (current, original, _table.Columns.Count);
366 /// Cancels the current edit on the row.
369 public void CancelEdit ()
371 //FIXME: original doesn't get erased on CancelEdit
373 if (HasVersion (DataRowVersion.Proposed))
377 rowState = DataRowState.Unchanged;
382 /// Clears the errors for the row, including the RowError and errors set with
385 public void ClearErrors ()
387 rowError = String.Empty;
388 columnErrors = new String[_table.Columns.Count];
392 /// Deletes the DataRow.
395 public void Delete ()
398 case DataRowState.Added:
399 Table.Rows.Remove (this);
401 case DataRowState.Deleted:
402 throw new DeletedRowInaccessibleException ();
404 //TODO: Events, Constraints
405 rowState = DataRowState.Deleted;
411 /// Ends the edit occurring on the row.
414 public void EndEdit ()
416 if (HasVersion (DataRowVersion.Proposed))
418 rowState = DataRowState.Modified;
420 //Calling next method validates UniqueConstraints
422 _table.Rows.ValidateDataRowInternal(this);
424 Array.Copy (proposed, current, _table.Columns.Count);
426 //FIXME: MS implementation assigns the proposed values to
427 //the original values. Should this be done here or on the
428 //AcceptChanges() method?
429 Array.Copy (proposed, original, _table.Columns.Count);
436 /// Gets the child rows of this DataRow using the specified DataRelation.
439 public DataRow[] GetChildRows (DataRelation relation)
441 throw new NotImplementedException ();
445 /// Gets the child rows of a DataRow using the specified RelationName of a
449 public DataRow[] GetChildRows (string relationName)
451 throw new NotImplementedException ();
455 /// Gets the child rows of a DataRow using the specified DataRelation, and
459 public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version)
461 throw new NotImplementedException ();
465 /// Gets the child rows of a DataRow using the specified RelationName of a
466 /// DataRelation, and DataRowVersion.
469 public DataRow[] GetChildRows (string relationName, DataRowVersion version)
471 throw new NotImplementedException ();
475 /// Gets the error description of the specified DataColumn.
477 public string GetColumnError (DataColumn column)
479 return GetColumnError (_table.Columns.IndexOf(column));
483 /// Gets the error description for the column specified by index.
485 public string GetColumnError (int columnIndex)
487 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
488 throw new IndexOutOfRangeException ();
490 return columnErrors[columnIndex];
494 /// Gets the error description for the column, specified by name.
496 public string GetColumnError (string columnName)
498 return GetColumnError (_table.Columns.IndexOf(columnName));
502 /// Gets an array of columns that have errors.
504 public DataColumn[] GetColumnsInError ()
506 ArrayList dataColumns = new ArrayList ();
508 for (int i = 0; i < columnErrors.Length; i += 1)
510 if (columnErrors[i] != String.Empty)
511 dataColumns.Add (_table.Columns[i]);
514 return (DataColumn[])(dataColumns.ToArray ());
518 /// Gets the parent row of a DataRow using the specified DataRelation.
521 public DataRow GetParentRow (DataRelation relation)
523 throw new NotImplementedException ();
527 /// Gets the parent row of a DataRow using the specified RelationName of a
531 public DataRow GetParentRow (string relationName)
533 throw new NotImplementedException ();
537 /// Gets the parent row of a DataRow using the specified DataRelation, and
541 public DataRow GetParentRow (DataRelation relation, DataRowVersion version)
543 throw new NotImplementedException ();
547 /// Gets the parent row of a DataRow using the specified RelationName of a
548 /// DataRelation, and DataRowVersion.
551 public DataRow GetParentRow (string relationName, DataRowVersion version)
553 throw new NotImplementedException ();
557 /// Gets the parent rows of a DataRow using the specified DataRelation.
560 public DataRow[] GetParentRows (DataRelation relation)
562 throw new NotImplementedException ();
566 /// Gets the parent rows of a DataRow using the specified RelationName of a
570 public DataRow[] GetParentRows (string relationName)
572 throw new NotImplementedException ();
576 /// Gets the parent rows of a DataRow using the specified DataRelation, and
580 public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version)
582 throw new NotImplementedException ();
586 /// Gets the parent rows of a DataRow using the specified RelationName of a
587 /// DataRelation, and DataRowVersion.
590 public DataRow[] GetParentRows (string relationName, DataRowVersion version)
592 throw new NotImplementedException ();
596 /// Gets a value indicating whether a specified version exists.
598 public bool HasVersion (DataRowVersion version)
602 case DataRowVersion.Default:
604 case DataRowVersion.Proposed:
605 return (proposed != null);
606 case DataRowVersion.Current:
607 return (current != null);
608 case DataRowVersion.Original:
609 return (original != null);
615 /// Gets a value indicating whether the specified DataColumn contains a null value.
617 public bool IsNull (DataColumn column)
619 return (this[column] == null);
623 /// Gets a value indicating whether the column at the specified index contains a null
626 public bool IsNull (int columnIndex)
628 return (this[columnIndex] == null);
632 /// Gets a value indicating whether the named column contains a null value.
634 public bool IsNull (string columnName)
636 return (this[columnName] == null);
640 /// Gets a value indicating whether the specified DataColumn and DataRowVersion
641 /// contains a null value.
643 public bool IsNull (DataColumn column, DataRowVersion version)
645 return (this[column, version] == null);
649 /// Rejects all changes made to the row since AcceptChanges was last called.
651 public void RejectChanges ()
653 // If original is null, then nothing has happened since AcceptChanges
654 // was last called. We have no "original" to go back to.
655 if (original != null)
657 Array.Copy (original, current, _table.Columns.Count);
661 case DataRowState.Added:
662 _table.Rows.Remove (this);
664 case DataRowState.Modified:
665 rowState = DataRowState.Unchanged;
667 case DataRowState.Deleted:
668 rowState = DataRowState.Unchanged;
672 _table.ChangedDataRow (this, DataRowAction.Rollback);
677 /// Sets the error description for a column specified as a DataColumn.
679 public void SetColumnError (DataColumn column, string error)
681 SetColumnError (_table.Columns.IndexOf (column), error);
685 /// Sets the error description for a column specified by index.
687 public void SetColumnError (int columnIndex, string error)
689 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
690 throw new IndexOutOfRangeException ();
691 columnErrors[columnIndex] = error;
695 /// Sets the error description for a column specified by name.
697 public void SetColumnError (string columnName, string error)
699 SetColumnError (_table.Columns.IndexOf (columnName), error);
703 /// Sets the value of the specified DataColumn to a null value.
706 protected void SetNull (DataColumn column)
708 throw new NotImplementedException ();
712 /// Sets the parent row of a DataRow with specified new parent DataRow.
715 public void SetParentRow (DataRow parentRow)
717 throw new NotImplementedException ();
721 /// Sets the parent row of a DataRow with specified new parent DataRow and
725 public void SetParentRow (DataRow parentRow, DataRelation relation)
727 throw new NotImplementedException ();
731 #endregion // Methods