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
46 public partial class DataRowCollection : InternalDataCollectionBase {
47 private DataTable table;
49 internal event ListChangedEventHandler ListChanged;
52 /// Internal constructor used to build a DataRowCollection.
54 internal DataRowCollection (DataTable table)
60 /// Gets the row at the specified index.
62 public DataRow this [int index] {
64 if (index < 0 || index >= Count)
65 throw new IndexOutOfRangeException ("There is no row at position " + index + ".");
67 return (DataRow) List [index];
72 /// Adds the specified DataRow to the DataRowCollection object.
74 public void Add (DataRow row)
78 throw new ArgumentNullException ("row", "'row' argument cannot be null.");
80 if (row.Table != this.table)
81 throw new ArgumentException ("This row already belongs to another table.");
83 // If row id is not -1, we know that it is in the collection.
85 throw new ArgumentException ("This row already belongs to this table.");
99 int IndexOf (DataRow row)
101 if (row == null || row.Table != table)
105 return (id >= 0 && id < List.Count && row == List [id]) ? id : -1;
108 internal void AddInternal (DataRow row)
110 AddInternal (row, DataRowAction.Add);
113 internal void AddInternal (DataRow row, DataRowAction action)
115 row.Table.ChangingDataRow (row, action);
117 row.AttachAt (List.Count - 1, action);
118 row.Table.ChangedDataRow (row, action);
120 row._rowChanged = false;
124 /// Creates a row using specified values and adds it to the DataRowCollection.
127 public DataRow Add (params object[] values)
129 public virtual DataRow Add (object[] values)
133 throw new NullReferenceException ();
134 DataRow row = table.NewNotInitializedRow ();
135 int newRecord = table.CreateRecord (values);
136 row.ImportRecord (newRecord);
144 /// Clears the collection of all rows.
148 if (this.table.DataSet != null && this.table.DataSet.EnforceConstraints) {
149 foreach (Constraint c in table.Constraints) {
150 UniqueConstraint uc = c as UniqueConstraint;
153 if (uc.ChildConstraint == null || uc.ChildConstraint.Table.Rows.Count == 0)
156 string err = String.Format ("Cannot clear table Parent because " +
157 "ForeignKeyConstraint {0} enforces Child.", uc.ConstraintName);
159 throw new InvalidConstraintException (err);
161 throw new ArgumentException (err);
167 table.DataTableClearing ();
171 // Remove from indexes
172 table.ResetIndexes ();
174 table.DataTableCleared ();
176 OnListChanged (this, new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
180 /// Gets a value indicating whether the primary key of any row in the collection contains
181 /// the specified value.
183 public bool Contains (object key)
185 return Find (key) != null;
189 /// Gets a value indicating whether the primary key column(s) of any row in the
190 /// collection contains the values specified in the object array.
192 public bool Contains (object [] keys)
194 return Find (keys) != null;
198 /// Gets the row specified by the primary key value.
200 public DataRow Find (object key)
202 return Find (new object []{key}, DataViewRowState.CurrentRows);
206 /// Gets the row containing the specified primary key values.
208 public DataRow Find (object[] keys)
210 return Find (keys, DataViewRowState.CurrentRows);
214 /// Gets the row containing the specified primary key values by searching the rows
215 /// filtered by the state.
217 internal DataRow Find (object [] keys, DataViewRowState rowStateFilter)
219 if (table.PrimaryKey.Length == 0)
220 throw new MissingPrimaryKeyException ("Table doesn't have a primary key.");
223 throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received 0 value(s).");
225 Index index = table.GetIndex (table.PrimaryKey, null, rowStateFilter, null, false);
226 int record = index.Find (keys);
228 if (record != -1 || !table._duringDataLoad)
229 return (record != -1 ? table.RecordCache [record] : null);
231 // If the key is not found using Index *and* if DataTable is under BeginLoadData
232 // then, check all the DataRows for the key
233 record = table.RecordCache.NewRecord ();
235 for (int i=0; i < table.PrimaryKey.Length; ++i)
236 table.PrimaryKey [i].DataContainer [record] = keys [i];
239 foreach (DataRow row in this) {
240 int rowIndex = Key.GetRecord (row, rowStateFilter);
245 for (int columnCnt = 0; columnCnt < table.PrimaryKey.Length; ++columnCnt) {
246 if (table.PrimaryKey [columnCnt].CompareValues (rowIndex, record) == 0)
256 table.RecordCache.DisposeRecord (record);
261 /// Inserts a new row into the collection at the specified location.
263 public void InsertAt (DataRow row, int pos)
266 throw new IndexOutOfRangeException ("The row insert position " + pos + " is invalid.");
269 throw new ArgumentNullException ("row", "'row' argument cannot be null.");
271 if (row.Table != this.table)
272 throw new ArgumentException ("This row already belongs to another table.");
274 // If row id is not -1, we know that it is in the collection.
276 throw new ArgumentException ("This row already belongs to this table.");
280 row.Table.ChangingDataRow (row, DataRowAction.Add);
282 if (pos >= List.Count) {
286 List.Insert (pos, row);
287 for (int i = pos+1; i < List.Count; i++)
288 ((DataRow) List [i]).RowID = i;
291 row.AttachAt (pos, DataRowAction.Add);
292 row.Table.ChangedDataRow (row, DataRowAction.Add);
296 /// Removes the specified DataRow from the internal list. Used by DataRow to commit the removing.
298 internal void RemoveInternal (DataRow row)
301 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
302 int index = List.IndexOf (row);
304 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
305 List.RemoveAt (index);
306 for (; index < List.Count; ++index)
307 ((DataRow) List [index]).RowID = index;
311 /// Removes the specified DataRow from the collection.
313 public void Remove (DataRow row)
315 if (IndexOf (row) < 0)
316 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
318 DataRowState state = row.RowState;
319 if (state != DataRowState.Deleted && state != DataRowState.Detached) {
321 // if the row was in added state it will be in Detached state after the
322 // delete operation, so we have to check it.
323 if (row.RowState != DataRowState.Detached)
324 row.AcceptChanges ();
329 /// Removes the row at the specified index from the collection.
331 public void RemoveAt (int index)
333 Remove (this [index]);
336 internal void OnListChanged (object sender, ListChangedEventArgs args)
338 if (ListChanged != null)
339 ListChanged (sender, args);
344 sealed partial class DataRowCollection {
345 public override int Count {
346 get { return List.Count; }
349 public void CopyTo (DataRow [] array, int index)
351 CopyTo ((Array) array, index);
354 public override void CopyTo (Array array, int index)
356 base.CopyTo (array, index);
359 public override IEnumerator GetEnumerator ()
361 return base.GetEnumerator ();
366 partial class DataRowCollection {
368 /// This member overrides InternalDataCollectionBase.List
370 protected override ArrayList List {
371 get { return base.List; }