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);
168 // Remove from indexes
169 table.ResetIndexes ();
171 OnListChanged (this, new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
175 /// Gets a value indicating whether the primary key of any row in the collection contains
176 /// the specified value.
178 public bool Contains (object key)
180 return Find (key) != null;
184 /// Gets a value indicating whether the primary key column(s) of any row in the
185 /// collection contains the values specified in the object array.
187 public bool Contains (object [] keys)
189 return Find (keys) != null;
193 /// Gets the row specified by the primary key value.
195 public DataRow Find (object key)
197 return Find (new object []{key}, DataViewRowState.CurrentRows);
201 /// Gets the row containing the specified primary key values.
203 public DataRow Find (object[] keys)
205 return Find (keys, DataViewRowState.CurrentRows);
209 /// Gets the row containing the specified primary key values by searching the rows
210 /// filtered by the state.
212 internal DataRow Find (object [] keys, DataViewRowState rowStateFilter)
214 if (table.PrimaryKey.Length == 0)
215 throw new MissingPrimaryKeyException ("Table doesn't have a primary key.");
218 throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received 0 value(s).");
220 Index index = table.GetIndex (table.PrimaryKey, null, rowStateFilter, null, false);
221 int record = index.Find (keys);
223 if (record != -1 || !table._duringDataLoad)
224 return (record != -1 ? table.RecordCache [record] : null);
226 // If the key is not found using Index *and* if DataTable is under BeginLoadData
227 // then, check all the DataRows for the key
228 record = table.RecordCache.NewRecord ();
230 for (int i=0; i < table.PrimaryKey.Length; ++i)
231 table.PrimaryKey [i].DataContainer [record] = keys [i];
234 foreach (DataRow row in this) {
235 int rowIndex = Key.GetRecord (row, rowStateFilter);
240 for (int columnCnt = 0; columnCnt < table.PrimaryKey.Length; ++columnCnt) {
241 if (table.PrimaryKey [columnCnt].CompareValues (rowIndex, record) == 0)
251 table.RecordCache.DisposeRecord (record);
256 /// Inserts a new row into the collection at the specified location.
258 public void InsertAt (DataRow row, int pos)
261 throw new IndexOutOfRangeException ("The row insert position " + pos + " is invalid.");
264 throw new ArgumentNullException ("row", "'row' argument cannot be null.");
266 if (row.Table != this.table)
267 throw new ArgumentException ("This row already belongs to another table.");
269 // If row id is not -1, we know that it is in the collection.
271 throw new ArgumentException ("This row already belongs to this table.");
275 row.Table.ChangingDataRow (row, DataRowAction.Add);
277 if (pos >= List.Count) {
281 List.Insert (pos, row);
282 for (int i = pos+1; i < List.Count; i++)
283 ((DataRow) List [i]).RowID = i;
286 row.AttachAt (pos, DataRowAction.Add);
287 row.Table.ChangedDataRow (row, DataRowAction.Add);
291 /// Removes the specified DataRow from the internal list. Used by DataRow to commit the removing.
293 internal void RemoveInternal (DataRow row)
296 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
297 int index = List.IndexOf (row);
299 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
300 List.RemoveAt (index);
301 for (; index < List.Count; ++index)
302 ((DataRow) List [index]).RowID = index;
306 /// Removes the specified DataRow from the collection.
308 public void Remove (DataRow row)
310 if (IndexOf (row) < 0)
311 throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
313 DataRowState state = row.RowState;
314 if (state != DataRowState.Deleted && state != DataRowState.Detached) {
316 // if the row was in added state it will be in Detached state after the
317 // delete operation, so we have to check it.
318 if (row.RowState != DataRowState.Detached)
319 row.AcceptChanges ();
324 /// Removes the row at the specified index from the collection.
326 public void RemoveAt (int index)
328 Remove (this [index]);
331 internal void OnListChanged (object sender, ListChangedEventArgs args)
333 if (ListChanged != null)
334 ListChanged (sender, args);
339 sealed partial class DataRowCollection {
340 public override int Count {
341 get { return List.Count; }
344 public void CopyTo (DataRow [] array, int index)
346 CopyTo ((Array) array, index);
349 public override void CopyTo (Array array, int index)
351 base.CopyTo (array, index);
354 public override IEnumerator GetEnumerator ()
356 return base.GetEnumerator ();
361 partial class DataRowCollection {
363 /// This member overrides InternalDataCollectionBase.List
365 protected override ArrayList List {
366 get { return base.List; }