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;
20 /// 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;
41 /// This member supports the .NET Framework infrastructure and is not intended to be
42 /// used directly from your code.
44 protected internal DataRow (DataRowBuilder builder)
46 _table = builder.Table;
50 current = new object[_table.Columns.Count];
52 columnErrors = new string[_table.Columns.Count];
53 rowError = String.Empty;
55 //rowState = DataRowState.Unchanged;
57 //on first creating a DataRow it is always detached.
58 rowState = DataRowState.Detached;
66 /// Gets a value indicating whether there are errors in a row.
68 public bool HasErrors {
71 throw new NotImplementedException ();
76 /// Gets or sets the data stored in the column specified by name.
78 public object this[string columnName] {
79 [MonoTODO] //FIXME: will return different values depending on DataRowState
80 get { return this[columnName, DataRowVersion.Current]; }
83 DataColumn column = _table.Columns[columnName];
85 throw new IndexOutOfRangeException ();
91 /// Gets or sets the data stored in specified DataColumn
93 public object this[DataColumn column] {
94 [MonoTODO] //FIXME: will return different values depending on DataRowState
95 get { return this[column, DataRowVersion.Current]; }
99 bool objIsDBNull = value.Equals(DBNull.Value);
101 throw new ArgumentNullException ();
102 int columnIndex = _table.Columns.IndexOf (column);
103 if (columnIndex == -1)
104 throw new ArgumentException ();
105 if(column.DataType != value.GetType ()) {
106 if(objIsDBNull == true && column.AllowDBNull == false)
107 throw new InvalidCastException ();
108 else if(objIsDBNull == false)
109 throw new InvalidCastException ();
111 if (rowState == DataRowState.Deleted)
112 throw new DeletedRowInaccessibleException ();
114 //MS Implementation doesn't seem to create the proposed or original
115 //set of values when a datarow has just been created or added to the
116 //DataTable and AcceptChanges() has not been called yet.
117 if(rowState == DataRowState.Detached || rowState == DataRowState.Added)
120 current[columnIndex] = DBNull.Value;
122 current[columnIndex] = value;
127 BeginEdit (); // implicitly called
129 proposed[columnIndex] = DBNull.Value;
131 proposed[columnIndex] = value;
134 //Don't know if this is the rigth thing to do,
135 //but it fixes my test. I believe the MS docs only say this
136 //method is implicitly called when calling AcceptChanges()
138 //EndEdit (); // is this the right thing to do?
144 /// Gets or sets the data stored in column specified by index.
146 public object this[int columnIndex] {
147 [MonoTODO] //FIXME: not always supposed to return current
148 get { return this[columnIndex, DataRowVersion.Current]; }
151 DataColumn column = _table.Columns[columnIndex]; //FIXME: will throw
153 throw new IndexOutOfRangeException ();
154 this[column] = value;
159 /// Gets the specified version of data stored in the named column.
161 public object this[string columnName, DataRowVersion version] {
164 DataColumn column = _table.Columns[columnName]; //FIXME: will throw
166 throw new IndexOutOfRangeException ();
167 return this[column, version];
172 /// Gets the specified version of data stored in the specified DataColumn.
174 public object this[DataColumn column, DataRowVersion version] {
177 throw new ArgumentNullException ();
179 int columnIndex = _table.Columns.IndexOf (column);
181 if (columnIndex == -1)
182 throw new ArgumentException ();
184 if (version == DataRowVersion.Default)
185 return column.DefaultValue;
187 if (!HasVersion (version))
188 throw new VersionNotFoundException ();
192 case DataRowVersion.Proposed:
193 return proposed[columnIndex];
194 case DataRowVersion.Current:
195 return current[columnIndex];
196 case DataRowVersion.Original:
197 return original[columnIndex];
199 throw new ArgumentException ();
205 /// Gets the data stored in the column, specified by index and version of the data to
208 public object this[int columnIndex, DataRowVersion version] {
211 DataColumn column = _table.Columns[columnIndex]; //FIXME: throws
213 throw new IndexOutOfRangeException ();
214 return this[column, version];
219 /// Gets or sets all of the values for this row through an array.
222 public object[] ItemArray {
223 get { return current; }
225 if (value.Length > _table.Columns.Count)
226 throw new ArgumentException ();
227 if (rowState == DataRowState.Deleted)
228 throw new DeletedRowInaccessibleException ();
230 for (int i = 0; i < value.Length; i += 1)
232 if (_table.Columns[i].ReadOnly && value[i] != this[i])
233 throw new ReadOnlyException ();
235 if (value[i] == null)
237 if (!_table.Columns[i].AllowDBNull)
238 throw new NoNullAllowedException ();
242 //FIXME: int strings can be converted to ints
243 if (_table.Columns[i].DataType != value[i].GetType())
244 throw new InvalidCastException ();
247 //FIXME: BeginEdit() not correct
248 BeginEdit (); // implicitly called
249 //FIXME: this isn't correct. a shorter array can set the first few values
250 //and not touch the rest. So not all the values will get replaced
256 /// Gets or sets the custom error description for a row.
258 public string RowError {
259 get { return rowError; }
260 set { rowError = value; }
264 /// Gets the current state of the row in regards to its relationship to the
265 /// DataRowCollection.
267 public DataRowState RowState {
268 get { return rowState; }
271 //FIXME?: Couldn't find a way to set the RowState when adding the DataRow
272 //to a Datatable so I added this method. Delete if there is a better way.
273 internal DataRowState RowStateInternal
275 set { rowState = value;}
279 /// Gets the DataTable for which this row has a schema.
281 public DataTable Table {
282 get { return _table; }
290 /// Commits all the changes made to this row since the last time AcceptChanges was
294 public void AcceptChanges ()
297 if(rowState == DataRowState.Added)
299 //Instantiate original and proposed values so that we can call
308 case DataRowState.Added:
309 rowState = DataRowState.Unchanged;
311 case DataRowState.Modified:
312 rowState = DataRowState.Unchanged;
314 case DataRowState.Deleted:
315 _table.Rows.Remove (this); //FIXME: this should occur in end edit
319 //MS implementation assigns the Proposed values
320 //to both current and original and keeps original after calling AcceptChanges
321 //Copy proposed to original in this.EndEdit()
326 /// Begins an edit operation on a DataRow object.
329 public void BeginEdit()
331 if (rowState == DataRowState.Deleted)
332 throw new DeletedRowInaccessibleException ();
334 if (!HasVersion (DataRowVersion.Proposed))
336 proposed = new object[_table.Columns.Count];
337 Array.Copy (current, proposed, _table.Columns.Count);
339 //TODO: Suspend validation
341 //FIXME: this doesn't happen on begin edit
342 if (!HasVersion (DataRowVersion.Original))
344 original = new object[_table.Columns.Count];
345 Array.Copy (current, original, _table.Columns.Count);
350 /// Cancels the current edit on the row.
353 public void CancelEdit ()
355 //FIXME: original doesn't get erased on CancelEdit
357 if (HasVersion (DataRowVersion.Proposed))
361 rowState = DataRowState.Unchanged;
366 /// Clears the errors for the row, including the RowError and errors set with
369 public void ClearErrors ()
371 rowError = String.Empty;
372 columnErrors = new String[_table.Columns.Count];
376 /// Deletes the DataRow.
379 public void Delete ()
381 if (rowState == DataRowState.Deleted)
382 throw new DeletedRowInaccessibleException ();
384 //TODO: Events, Constraints
385 rowState = DataRowState.Deleted;
389 /// Ends the edit occurring on the row.
392 public void EndEdit ()
394 if (HasVersion (DataRowVersion.Proposed))
396 rowState = DataRowState.Modified;
397 //TODO: Validate Constraints, Events
398 Array.Copy (proposed, current, _table.Columns.Count);
400 //FIXME: MS implementation assigns the proposed values to
401 //the original values. Should this be done here or on the
402 //AcceptChanges() method?
403 Array.Copy (proposed, original, _table.Columns.Count);
410 /// Gets the child rows of this DataRow using the specified DataRelation.
413 public DataRow[] GetChildRows (DataRelation relation)
415 throw new NotImplementedException ();
419 /// Gets the child rows of a DataRow using the specified RelationName of a
423 public DataRow[] GetChildRows (string relationName)
425 throw new NotImplementedException ();
429 /// Gets the child rows of a DataRow using the specified DataRelation, and
433 public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version)
435 throw new NotImplementedException ();
439 /// Gets the child rows of a DataRow using the specified RelationName of a
440 /// DataRelation, and DataRowVersion.
443 public DataRow[] GetChildRows (string relationName, DataRowVersion version)
445 throw new NotImplementedException ();
449 /// Gets the error description of the specified DataColumn.
451 public string GetColumnError (DataColumn column)
453 return GetColumnError (_table.Columns.IndexOf(column));
457 /// Gets the error description for the column specified by index.
459 public string GetColumnError (int columnIndex)
461 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
462 throw new IndexOutOfRangeException ();
464 return columnErrors[columnIndex];
468 /// Gets the error description for the column, specified by name.
470 public string GetColumnError (string columnName)
472 return GetColumnError (_table.Columns.IndexOf(columnName));
476 /// Gets an array of columns that have errors.
478 public DataColumn[] GetColumnsInError ()
480 ArrayList dataColumns = new ArrayList ();
482 for (int i = 0; i < columnErrors.Length; i += 1)
484 if (columnErrors[i] != String.Empty)
485 dataColumns.Add (_table.Columns[i]);
488 return (DataColumn[])(dataColumns.ToArray ());
492 /// Gets the parent row of a DataRow using the specified DataRelation.
495 public DataRow GetParentRow (DataRelation relation)
497 throw new NotImplementedException ();
501 /// Gets the parent row of a DataRow using the specified RelationName of a
505 public DataRow GetParentRow (string relationName)
507 throw new NotImplementedException ();
511 /// Gets the parent row of a DataRow using the specified DataRelation, and
515 public DataRow GetParentRow (DataRelation relation, DataRowVersion version)
517 throw new NotImplementedException ();
521 /// Gets the parent row of a DataRow using the specified RelationName of a
522 /// DataRelation, and DataRowVersion.
525 public DataRow GetParentRow (string relationName, DataRowVersion version)
527 throw new NotImplementedException ();
531 /// Gets the parent rows of a DataRow using the specified DataRelation.
534 public DataRow[] GetParentRows (DataRelation relation)
536 throw new NotImplementedException ();
540 /// Gets the parent rows of a DataRow using the specified RelationName of a
544 public DataRow[] GetParentRows (string relationName)
546 throw new NotImplementedException ();
550 /// Gets the parent rows of a DataRow using the specified DataRelation, and
554 public DataRow[] GetParentRows (DataRelation relation, DataRowVersion version)
556 throw new NotImplementedException ();
560 /// Gets the parent rows of a DataRow using the specified RelationName of a
561 /// DataRelation, and DataRowVersion.
564 public DataRow[] GetParentRows (string relationName, DataRowVersion version)
566 throw new NotImplementedException ();
570 /// Gets a value indicating whether a specified version exists.
572 public bool HasVersion (DataRowVersion version)
576 case DataRowVersion.Default:
578 case DataRowVersion.Proposed:
579 return (proposed != null);
580 case DataRowVersion.Current:
581 return (current != null);
582 case DataRowVersion.Original:
583 return (original != null);
589 /// Gets a value indicating whether the specified DataColumn contains a null value.
591 public bool IsNull (DataColumn column)
593 return (this[column] == null);
597 /// Gets a value indicating whether the column at the specified index contains a null
600 public bool IsNull (int columnIndex)
602 return (this[columnIndex] == null);
606 /// Gets a value indicating whether the named column contains a null value.
608 public bool IsNull (string columnName)
610 return (this[columnName] == null);
614 /// Gets a value indicating whether the specified DataColumn and DataRowVersion
615 /// contains a null value.
617 public bool IsNull (DataColumn column, DataRowVersion version)
619 return (this[column, version] == null);
623 /// Rejects all changes made to the row since AcceptChanges was last called.
625 public void RejectChanges ()
627 // If original is null, then nothing has happened since AcceptChanges
628 // was last called. We have no "original" to go back to.
629 if (original != null)
631 Array.Copy (original, current, _table.Columns.Count);
635 case DataRowState.Added:
636 _table.Rows.Remove (this);
638 case DataRowState.Modified:
639 rowState = DataRowState.Unchanged;
641 case DataRowState.Deleted:
642 rowState = DataRowState.Unchanged;
649 /// Sets the error description for a column specified as a DataColumn.
651 public void SetColumnError (DataColumn column, string error)
653 SetColumnError (_table.Columns.IndexOf (column), error);
657 /// Sets the error description for a column specified by index.
659 public void SetColumnError (int columnIndex, string error)
661 if (columnIndex < 0 || columnIndex >= columnErrors.Length)
662 throw new IndexOutOfRangeException ();
663 columnErrors[columnIndex] = error;
667 /// Sets the error description for a column specified by name.
669 public void SetColumnError (string columnName, string error)
671 SetColumnError (_table.Columns.IndexOf (columnName), error);
675 /// Sets the value of the specified DataColumn to a null value.
678 protected void SetNull (DataColumn column)
680 throw new NotImplementedException ();
684 /// Sets the parent row of a DataRow with specified new parent DataRow.
687 public void SetParentRow (DataRow parentRow)
689 throw new NotImplementedException ();
693 /// Sets the parent row of a DataRow with specified new parent DataRow and
697 public void SetParentRow (DataRow parentRow, DataRelation relation)
699 throw new NotImplementedException ();
703 #endregion // Methods