X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Data%2FSystem.Data%2FDataRowCollection.cs;h=a3cbb45804e42ff47a371aa07769f1472cb1c2ae;hb=2a8259225695032220537b3c90a99d7a2686f214;hp=bb74b7170796b1fe4cb9340294b32323f92349a5;hpb=aad18f162af0a629988f9d5e86c2c19b573862b2;p=mono.git diff --git a/mcs/class/System.Data/System.Data/DataRowCollection.cs b/mcs/class/System.Data/System.Data/DataRowCollection.cs index bb74b717079..a3cbb45804e 100644 --- a/mcs/class/System.Data/System.Data/DataRowCollection.cs +++ b/mcs/class/System.Data/System.Data/DataRowCollection.cs @@ -10,9 +10,33 @@ // (C) Copyright 2002 Daniel Morgan // +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + using System; using System.Collections; using System.ComponentModel; +using System.Data.Common; namespace System.Data { @@ -38,10 +62,10 @@ namespace System.Data public DataRow this[int index] { get { - if (index >= Count) + if (index < 0 || index >= Count) throw new IndexOutOfRangeException ("There is no row at position " + index + "."); - return (DataRow) list[index]; + return (DataRow) List[index]; } } @@ -50,7 +74,7 @@ namespace System.Data /// protected override ArrayList List { - get { return list; } + get { return base.List; } } /// @@ -62,14 +86,28 @@ namespace System.Data if (row == null) throw new ArgumentNullException("row", "'row' argument cannot be null."); - if (list.IndexOf(row) != -1) + if (row.Table != this.table) + throw new ArgumentException ("This row already belongs to another table."); + + // If row id is not -1, we know that it is in the collection. + if (row.RowID != -1) throw new ArgumentException ("This row already belongs to this table."); - if (table.DataSet == null || table.DataSet.EnforceConstraints) + row.BeginEdit(); + + if ((table.DataSet == null || table.DataSet.EnforceConstraints) && !table._duringDataLoad) // we have to check that the new row doesn't colide with existing row ValidateDataRowInternal(row); - - list.Add (row); + + AddInternal(row); + } + + internal void AddInternal(DataRow row) { + row.Table.ChangingDataRow (row, DataRowAction.Add); + row.HasParentCollection = true; + List.Add (row); + // Set the row id. + row.RowID = List.Count - 1; row.AttachRow (); row.Table.ChangedDataRow (row, DataRowAction.Add); } @@ -77,11 +115,19 @@ namespace System.Data /// /// Creates a row using specified values and adds it to the DataRowCollection. /// +#if NET_2_0 + public virtual DataRow Add (params object[] values) +#else public virtual DataRow Add (object[] values) +#endif { - DataRow row = table.NewRow (); - row.ItemArray = values; - Add (row); + DataRow row = table.NewNotInitializedRow(); + int newRecord = table.CreateRecord(values); + row.ImportRecord(newRecord); + if ((table.DataSet == null || table.DataSet.EnforceConstraints) && !table._duringDataLoad) + // we have to check that the new row doesn't colide with existing row + ValidateDataRowInternal(row); + AddInternal (row); return row; } @@ -90,21 +136,32 @@ namespace System.Data /// public void Clear () { - if (this.table.DataSet != null) - { - foreach (DataTable table in this.table.DataSet.Tables) - { - foreach (Constraint c in table.Constraints) - { - if (c is ForeignKeyConstraint) - { - if (((ForeignKeyConstraint) c).RelatedTable.Equals(this.table)) - throw new InvalidConstraintException("Cannot clear table Parent because ForeignKeyConstraint " + c.ConstraintName + " enforces Child."); + if (this.table.DataSet != null && this.table.DataSet.EnforceConstraints) { + foreach (DataTable table in this.table.DataSet.Tables) { + foreach (Constraint c in table.Constraints) { + if (c is ForeignKeyConstraint) { + ForeignKeyConstraint fk = (ForeignKeyConstraint) c; + if (fk.RelatedTable.Equals(this.table) + && fk.Table.Rows.Count > 0) // check does not make sense if we don't have rows +#if NET_1_1 + throw new InvalidConstraintException (String.Format ("Cannot clear table Parent" + + " because ForeignKeyConstraint "+ + "{0} enforces Child.", + c.ConstraintName)); +#else + throw new ArgumentException (String.Format ("Cannot clear table Parent because " + + "ForeignKeyConstraint {0} enforces Child.", + c.ConstraintName)); +#endif } } } } - list.Clear (); + // Remove from indexes + for (int i = 0; i < this.Count; i++) + this.table.DeleteRowFromIndexes (this [i]); + + List.Clear (); } /// @@ -122,103 +179,63 @@ namespace System.Data /// public bool Contains (object[] keys) { - if (table.PrimaryKey.Length != keys.Length) - throw new ArgumentException ("Expecting " + table.PrimaryKey.Length + " value(s) for the key " + - "being indexed, but received " + keys.Length + " value(s)."); - return Find (keys) != null; } /// /// Gets the row specified by the primary key value. /// - [MonoTODO] public DataRow Find (object key) { - if (table.PrimaryKey.Length == 0) - throw new MissingPrimaryKeyException ("Table doesn't have a primary key."); - if (table.PrimaryKey.Length > 1) - throw new ArgumentException ("Expecting " + table.PrimaryKey.Length + - " value(s) for the key being indexed, but received 1 value(s)."); - - string primColumnName = table.PrimaryKey [0].ColumnName; - Type coltype = null; - object newKey = null; - - foreach (DataRow row in this) { - - if (row.RowState != DataRowState.Deleted) - { - object primValue = row [primColumnName]; - if (key == null) - { - if (primValue == null) - return row; - else - continue; - } - - newKey = Convert.ChangeType (key, Type.GetTypeCode(primValue.GetType ())); - - if (primValue.Equals (newKey)) - return row; - } - } - - // FIXME: is the correct value null? - return null; - } + return Find(new object[]{key}); + } /// /// Gets the row containing the specified primary key values. /// - [MonoTODO] - public DataRow Find (object[] keys) + public DataRow Find (object[] keys) { if (table.PrimaryKey.Length == 0) throw new MissingPrimaryKeyException ("Table doesn't have a primary key."); - string [] primColumnNames = new string [table.PrimaryKey.Length]; - - for (int i = 0; i < primColumnNames.Length; i++) - primColumnNames [i] = table.PrimaryKey [i].ColumnName; + if (keys == null) + throw new ArgumentException ("Expecting " + table.PrimaryKey.Length +" value(s) for the key being indexed, but received 0 value(s)."); + + Index index = table.GetIndex(table.PrimaryKey,null,DataViewRowState.None,null,false); - Type coltype = null; - object newKey = null; - - foreach (DataRow row in this) { - - if (row.RowState != DataRowState.Deleted) - { - bool eq = true; - for (int i = 0; i < keys.Length; i++) - { - - object primValue = row [primColumnNames [i]]; - object keyValue = keys [i]; - if (keyValue == null) - { - if (primValue == null) - return row; - else - continue; + int record = index.Find(keys); + return (record != -1) ? table.RecordCache[record] : null; + } + + internal DataRow Find(int index) + { + DataColumn[] primaryKey = table.PrimaryKey; + Index primaryKeyIndex = table.FindIndex(primaryKey); + // if we can search through index + if (primaryKeyIndex != null) { + // get the child rows from the index + int record = primaryKeyIndex.Find(index); + if ( record != -1 ) { + return table.RecordCache[record]; + } + } + else { + //loop through all collection rows + foreach (DataRow row in this) { + if (row.RowState != DataRowState.Deleted) { + int rowIndex = row.IndexFromVersion(DataRowVersion.Default); + bool match = true; + for (int columnCnt = 0; columnCnt < primaryKey.Length; ++columnCnt) { + if (primaryKey[columnCnt].DataContainer.CompareValues(rowIndex, index) != 0) { + match = false; + } + } + if ( match ) { + return row; } - - newKey = Convert.ChangeType (keyValue, Type.GetTypeCode(primValue.GetType ())); - - if (!primValue.Equals (newKey)) - { - eq = false; - break; - } } - - if (eq) - return row; } } - - // FIXME: is the correct value null? return null; } @@ -229,11 +246,52 @@ namespace System.Data { if (pos < 0) throw new IndexOutOfRangeException ("The row insert position " + pos + " is invalid."); + + if (row == null) + throw new ArgumentNullException("row", "'row' argument cannot be null."); + + if (row.Table != this.table) + throw new ArgumentException ("This row already belongs to another table."); + + // If row id is not -1, we know that it is in the collection. + if (row.RowID != -1) + throw new ArgumentException ("This row already belongs to this table."); + + if ((table.DataSet == null || table.DataSet.EnforceConstraints) && !table._duringDataLoad) + // we have to check that the new row doesn't colide with existing row + ValidateDataRowInternal(row); - if (pos >= list.Count) - list.Add (row); - else - list.Insert (pos, row); + row.Table.ChangingDataRow (row, DataRowAction.Add); + + if (pos >= List.Count) { + row.RowID = List.Count; + List.Add (row); + } + else { + List.Insert (pos, row); + row.RowID = pos; + for (int i = pos+1; i < List.Count; i++) { + ((DataRow)List [i]).RowID = i; + } + } + + row.HasParentCollection = true; + row.AttachRow (); + row.Table.ChangedDataRow (row, DataRowAction.Add); + } + + /// + /// Removes the specified DataRow from the internal list. Used by DataRow to commit the removing. + /// + internal void RemoveInternal (DataRow row) { + if (row == null) { + throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection."); + } + int index = List.IndexOf(row); + if (index < 0) { + throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection."); + } + List.RemoveAt(index); } /// @@ -241,12 +299,18 @@ namespace System.Data /// public void Remove (DataRow row) { - if (row == null) + if (!List.Contains(row)) throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection."); - int index = list.IndexOf(row); - if (index < 0) - throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection."); - RemoveAt(index); + + DataRowState state = row.RowState; + if (state != DataRowState.Deleted && + state != DataRowState.Detached) { + row.Delete(); + // if the row was in added state it will be in Detached state after the + // delete operation, so we have to check it. + if (row.RowState != DataRowState.Detached) + row.AcceptChanges(); + } } /// @@ -254,15 +318,7 @@ namespace System.Data /// public void RemoveAt (int index) { - if (index < 0 || index >= list.Count) - throw new IndexOutOfRangeException ("There is no row at position " + index + "."); - - DataRow row = (DataRow)list [index]; - if (row.RowState != DataRowState.Deleted && row.RowState != DataRowState.Added) - row.Delete(); - list.RemoveAt (index); - row.DetachRow(); - table.DeletedDataRow (row, DataRowAction.Delete); + Remove(this[index]); } /// @@ -272,17 +328,30 @@ namespace System.Data [MonoTODO] internal void ValidateDataRowInternal(DataRow row) { - //FIXME: this validates constraints in the order they appear - //in the collection. Most probably we need to do it in a - //specific order like unique/primary keys first, then Foreignkeys, etc - foreach(Constraint constraint in table.Constraints) - { - constraint.AssertConstraint(row); + //first check for null violations. + row._nullConstraintViolation = true; + row.CheckNullConstraints(); + + int newRecord = (row.Proposed >= 0) ? row.Proposed : row.Current; + if (newRecord < 0) + return; + + foreach(Index index in table.Indexes) { + index.Update(row,newRecord); } + foreach(Constraint constraint in table.Constraints) { + try { + constraint.AssertConstraint(row); + } + catch(Exception e) { + // remove row from indexes + foreach(Index index in table.Indexes) { + index.Delete(newRecord); + } + throw e; + } + } } - } - - }