2 // System.Data.DataRowCollection.cs
5 // Daniel Morgan <danmorg@sc.rr.com>
6 // Tim Coleman <tim@timcoleman.com>
8 // (C) Ximian, Inc 2002
9 // (C) Copyright 2002 Tim Coleman
10 // (C) Copyright 2002 Daniel Morgan
14 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 using System.Collections;
38 using System.ComponentModel;
39 using System.Data.Common;
44 /// Collection of DataRows in a DataTable
54 class DataRowCollection : InternalDataCollectionBase
56 private DataTable table;
58 internal event ListChangedEventHandler ListChanged;
61 /// Internal constructor used to build a DataRowCollection.
63 internal DataRowCollection (DataTable table) : base ()
69 /// Gets the row at the specified index.
71 public DataRow this[int index]
74 if (index < 0 || index >= Count)
75 throw new IndexOutOfRangeException ("There is no row at position " + index + ".");
77 return (DataRow) List[index];
82 public override int Count {
91 /// This member overrides InternalDataCollectionBase.List
93 protected override ArrayList List
95 get { return base.List; }
100 /// Adds the specified DataRow to the DataRowCollection object.
102 public void Add (DataRow row)
106 throw new ArgumentNullException("row", "'row' argument cannot be null.");
108 if (row.Table != this.table)
109 throw new ArgumentException ("This row already belongs to another table.");
111 // If row id is not -1, we know that it is in the collection.
113 throw new ArgumentException ("This row already belongs to this table.");
127 int IndexOf (DataRow row)
133 foreach (DataRow dr in this) {
143 internal void AddInternal (DataRow row) {
144 AddInternal (row, DataRowAction.Add);
147 internal void AddInternal(DataRow row, DataRowAction action) {
148 row.Table.ChangingDataRow (row, action);
149 row.HasParentCollection = true;
152 row.RowID = List.Count - 1;
155 if ((action & (DataRowAction.ChangeCurrentAndOriginal |
156 DataRowAction.ChangeOriginal)) != 0)
157 row.Original = row.Current;
159 row.Table.ChangedDataRow (row, action);
161 row._rowChanged = false;
165 /// Creates a row using specified values and adds it to the DataRowCollection.
168 public DataRow Add (params object[] values)
170 public virtual DataRow Add (object[] values)
174 throw new NullReferenceException ();
175 DataRow row = table.NewNotInitializedRow();
176 int newRecord = table.CreateRecord(values);
177 row.ImportRecord(newRecord);
185 /// Clears the collection of all rows.
189 if (this.table.DataSet != null && this.table.DataSet.EnforceConstraints) {
190 foreach (Constraint c in table.Constraints) {
191 UniqueConstraint uc = c as UniqueConstraint;
194 if (uc.ChildConstraint == null || uc.ChildConstraint.Table.Rows.Count == 0)
197 string err = String.Format ("Cannot clear table Parent because " +
198 "ForeignKeyConstraint {0} enforces Child.", uc.ConstraintName);
200 throw new InvalidConstraintException (err);
202 throw new ArgumentException (err);
209 // Remove from indexes
210 table.ResetIndexes ();
212 OnListChanged (this, new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
216 /// Gets a value indicating whether the primary key of any row in the collection contains
217 /// the specified value.
219 public bool Contains (object key)
221 return Find (key) != null;
225 /// Gets a value indicating whether the primary key column(s) of any row in the
226 /// collection contains the values specified in the object array.
228 public bool Contains (object[] keys)
230 return Find (keys) != null;
234 public void CopyTo (DataRow [] array, int index)
236 CopyTo ((Array) array, index);
239 public override void CopyTo (Array array, int index)
241 base.CopyTo (array, index);
244 public override IEnumerator GetEnumerator ()
246 return base.GetEnumerator ();
251 /// Gets the row specified by the primary key value.
253 public DataRow Find (object key)
255 return Find (new object[]{key}, DataViewRowState.CurrentRows);
259 /// Gets the row containing the specified primary key values.
261 public DataRow Find (object[] keys)
263 return Find (keys, DataViewRowState.CurrentRows);
267 /// Gets the row containing the specified primary key values by searching the rows
268 /// filtered by the state.
270 internal DataRow Find (object [] keys, DataViewRowState rowStateFilter)
272 if (table.PrimaryKey.Length == 0)
273 throw new MissingPrimaryKeyException ("Table doesn't have a primary key.");
276 throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received 0 value(s).");
278 Index index = table.GetIndex (table.PrimaryKey, null, rowStateFilter, null, false);
279 int record = index.Find (keys);
281 if (record != -1 || !table._duringDataLoad)
282 return (record != -1 ? table.RecordCache [record] : null);
284 // If the key is not found using Index *and* if DataTable is under BeginLoadData
285 // then, check all the DataRows for the key
286 record = table.RecordCache.NewRecord ();
288 for (int i=0; i < table.PrimaryKey.Length; ++i)
289 table.PrimaryKey [i].DataContainer [record] = keys [i];
292 foreach (DataRow row in this) {
294 int rowIndex = Key.GetRecord (row, rowStateFilter);
299 for (int columnCnt = 0; columnCnt < table.PrimaryKey.Length; ++columnCnt) {
300 if (table.PrimaryKey [columnCnt].CompareValues (rowIndex, record) == 0)
310 table.RecordCache.DisposeRecord (record);
315 /// Inserts a new row into the collection at the specified location.
317 public void InsertAt (DataRow row, int pos)
320 throw new IndexOutOfRangeException ("The row insert position " + pos + " is invalid.");
323 throw new ArgumentNullException("row", "'row' argument cannot be null.");
325 if (row.Table != this.table)
326 throw new ArgumentException ("This row already belongs to another table.");
328 // If row id is not -1, we know that it is in the collection.
330 throw new ArgumentException ("This row already belongs to this table.");
334 row.Table.ChangingDataRow (row, DataRowAction.Add);
336 if (pos >= List.Count) {
337 row.RowID = List.Count;
341 List.Insert (pos, row);
343 for (int i = pos+1; i < List.Count; i++) {
344 ((DataRow)List [i]).RowID = i;
348 row.HasParentCollection = true;
350 row.Table.ChangedDataRow (row, DataRowAction.Add);
354 /// Removes the specified DataRow from the internal list. Used by DataRow to commit the removing.
356 internal void RemoveInternal (DataRow row) {
358 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
360 int index = List.IndexOf(row);
362 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
364 List.RemoveAt(index);
368 /// Removes the specified DataRow from the collection.
370 public void Remove (DataRow row)
372 if (!List.Contains(row))
373 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
375 DataRowState state = row.RowState;
376 if (state != DataRowState.Deleted &&
377 state != DataRowState.Detached) {
379 // if the row was in added state it will be in Detached state after the
380 // delete operation, so we have to check it.
381 if (row.RowState != DataRowState.Detached)
387 /// Removes the row at the specified index from the collection.
389 public void RemoveAt (int index)
394 internal void OnListChanged (object sender, ListChangedEventArgs args)
396 if (ListChanged != null)
397 ListChanged (sender, args);