* DbDataAdapter.cs (Fill): Patch from Eran Domb, <eran@mainsoft.com>.
Fixes a possible NullReferenceException, more details here:
* DataColumn.cs (Unique): Implemented.
* DataTable.cs:
* ConstraintCollection.cs:
* ForeignKeyConstraint.cs (_ensureUniqueConstraintExists): Fixes
an Exception thrown. Details:
http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002130.html
* DataRowCollection.cs (Add): There is no checking that there is
no violation of the unique constrains.
* UniqueConstraint.cs (AssertConstraint): There is no checking on
all columns in the constraint.
svn path=/trunk/mcs/; revision=18298
+2003-09-25 Duncan Mak <duncan@ximian.com>
+
+ * DbDataAdapter.cs (Fill): Patch from Eran Domb, <eran@mainsoft.com>.
+ Fixes a possible NullReferenceException, more details here:
+
+ http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002116.html
+
2003-09-21 eran <erand@mainsoft.com>
* DbDataRecord.cs: The method
dataTable = new DataTable ();
SetupSchema (SchemaType.Mapped, tableName, dataTable);
- if (dataSet.Tables.Contains (dataTable.TableName))
- dataTable = dataSet.Tables [tableName];
+ // check if the table exists in the dataset
+ if (dataSet.Tables.Contains (dataTable.TableName))
+ // get the table from the dataset
+ dataTable = dataSet.Tables [dataTable.TableName];
+ else
+ dataSet.Tables.Add (dataTable);
BuildSchema (dataReader, dataTable, SchemaType.Mapped);
for (int i = 0; i < startRecord; i += 1)
}
}
- dataSet.Tables.Add (dataTable);
tableName = String.Format ("{0}{1}", srcTable, ++resultIndex);
startRecord = 0;
int index = 0;
do {
+ // FixMe: Allocate table only if it doesn't exist already!
DataTable table = new DataTable ();
SetupSchema (schemaType, tableName, table);
if (dataSet.Tables.Contains (table.TableName))
+2003-09-25 Duncan Mak <duncan@ximian.com>
+
+ Patches from Eran Domb <erand@mainsoft.com>.
+
+ * DataColumn.cs (Unique): Implemented.
+
+ * DataTable.cs:
+ * ConstraintCollection.cs:
+ * ForeignKeyConstraint.cs (_ensureUniqueConstraintExists): Fixes
+ an Exception thrown. Details:
+ http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002130.html
+
+ * DataRowCollection.cs (Add): There is no checking that there is
+ no violation of the unique constrains.
+
+ * UniqueConstraint.cs (AssertConstraint): There is no checking on
+ all columns in the constraint.
+
+ * DataTableCollection (Add): Correctly throw an Exception, more
+ details here:
+ http://lists.ximian.com/archives/public/mono-devel-list/2003-September/002117.html
+ (Remove, RemoveAt): Implemented.
+
2003-07-31 Duncan Mak <duncan@ximian.com>
* DBConcurrencyException.cs: Added new NET_1_1 no-param constructor.
public event CollectionChangeEventHandler CollectionChanged;
internal event DelegateValidateRemoveConstraint ValidateRemoveConstraint;
-
+ private DataTable table;
//Don't allow public instantiation
//Will be instantianted from DataTable
- internal ConstraintCollection(){}
+ internal ConstraintCollection(DataTable table){
+ this.table = table;
+ }
+
+ internal DataTable Table{
+ get{
+ return this.table;
+ }
+ }
public virtual Constraint this[string name] {
get {
failReason = tmp;
return !cancel;
}
+
}
}
if( value )
{
+ if (Expression != null && Expression != "")
+ throw new ArgumentException("Cannot change Unique property for the expression column.");
if( _table != null )
{
UniqueConstraint uc = new UniqueConstraint(this);
{
if( _table != null )
{
- //FIXME: Add code to remove constraint from DataTable
- throw new NotImplementedException ();
+ ConstraintCollection cc = _table.Constraints;
+ //foreach (Constraint c in cc)
+ for (int i = 0; i < cc.Count; i++)
+ {
+ Constraint c = cc[i];
+ if (c is UniqueConstraint)
+ {
+ DataColumn[] cols = ((UniqueConstraint)c).Columns;
+
+ if (cols.Length == 1 && cols[0] == this)
+ {
+ if (!cc.CanRemove(c))
+ throw new ArgumentException("Cannot remove unique constraint '" + c.ConstraintName + "'. Remove foreign key constraint first.");
+
+ cc.Remove(c);
+ }
+
+ }
+ }
}
}
if (list.IndexOf(row) != -1)
throw new ArgumentException ("This row already belongs to this table.");
-
+
+ if (table.DataSet.EnforceConstraints)
+ // we have to check that the new row doesn't colide with existing row
+ ValidateDataRowInternal(row);
+
list.Add (row);
row.AttachRow ();
row.Table.ChangedDataRow (row, DataRowAction.Add);
}
}
-
+
}
+
+
}
{
dataSet = null;
_columnCollection = new DataColumnCollection(this);
- _constraintCollection = new ConstraintCollection();
+ _constraintCollection = new ConstraintCollection(this);
_extendedProperties = new PropertyCollection();
_tableName = "";
_nameSpace = null;
public virtual void Add (DataTable table)
{
+
+ // check if the reference is a null reference
+ if(table == null)
+ throw new ArgumentNullException("table");
+
+ // check if the list already contains this tabe.
+ if(list.Contains(table))
+ throw new ArgumentException("DataTable already belongs to this DataSet.");
+
+ // if the table name is null or empty string.
+ // give her a name.
if (table.TableName == null || table.TableName == string.Empty)
NameTable (table);
+
+ // check if the collection has a table with the same name.
+ if(Contains(table.TableName))
+ throw new DuplicateNameException("A DataTable named '" + table.TableName + "' already belongs to this DataSet.");
list.Add (table);
table.dataSet = dataSet;
[MonoTODO]
public bool CanRemove (DataTable table)
{
- throw new NotImplementedException ();
+ return CanRemove(table, false);
}
public void Clear ()
public void Remove (DataTable table)
{
- this.Remove (table.TableName);
+ CanRemove(table, true);
+ list.Remove(table);
OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, table));
}
public void Remove (string name)
{
- list.Remove (this [name]);
+ Remove (this [name]);
}
public void RemoveAt (int index)
{
+ DataTable t = this[index];
+ CanRemove(t, true);
list.RemoveAt (index);
+ OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, t));
}
#endregion
Table.TableName = Name + i;
}
+
+ // check if a table can be removed from this collectiuon.
+ // if the table can not be remved act according to throwException parameter.
+ // if it is true throws an Exception, else return false.
+ private bool CanRemove(DataTable table, bool throwException)
+ {
+ // check if table is null reference
+ if (table == null)
+ {
+ if(throwException)
+ throw new ArgumentNullException("table");
+ return false;
+ }
+
+ // check if the table has the same DataSet as this collection.
+ if(table.DataSet != this.dataSet)
+ {
+ if(throwException)
+ throw new ArgumentException("Table " + table.TableName + " does not belong to this DataSet.");
+ return false;
+ }
+
+ // check the table has a relation attached to it.
+ if (table.ParentRelations.Count > 0 || table.ChildRelations.Count > 0)
+ {
+ if(throwException)
+ throw new ArgumentException("Cannot remove a table that has existing relations. Remove relations first.");
+ return false;
+ }
+
+
+ // now we check if any ForeignKeyConstraint is referncing 'table'.
+ IEnumerator tableEnumerator = this.dataSet.Tables.GetEnumerator();
+
+ // loop on all tables in dataset
+ while (tableEnumerator.MoveNext())
+ {
+ IEnumerator constraintEnumerator = ((DataTable) tableEnumerator.Current).Constraints.GetEnumerator();
+ // loop on all constrains in the current table
+ while (constraintEnumerator.MoveNext())
+ {
+ Object o = (Constraint) constraintEnumerator.Current;
+ // we only check ForeignKeyConstraint
+ if (o is ForeignKeyConstraint)
+ {
+ ForeignKeyConstraint fc = (ForeignKeyConstraint) o;
+ if(fc.Table == table || fc.RelatedTable == table)
+ {
+ if(throwException)
+ throw new ArgumentException("Cannot remove table " + table.TableName + ", because it referenced in ForeignKeyConstraint " + fc.ConstraintName + ". Remove the constraint first.");
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
#endregion // Private methods
//see if unique constraint already exists
//if not create unique constraint
- uc = UniqueConstraint.GetUniqueConstraintForColumnSet(collection, parentColumns);
+ if(parentColumns[0] != null)
+ uc = UniqueConstraint.GetUniqueConstraintForColumnSet(parentColumns[0].Table.Constraints, parentColumns);
- if (null == uc) uc = new UniqueConstraint(parentColumns, false); //could throw
+ if (null == uc) {
+ uc = new UniqueConstraint(parentColumns, false); //could throw
+ parentColumns [0].Table.Constraints.Add (uc);
+ }
//keep reference
_parentUniqueConstraint = uc;
- parentColumns [0].Table.Constraints.Add (uc);
+ //parentColumns [0].Table.Constraints.Add (uc);
//if this unique constraint is attempted to be removed before us
//we can fail the validation
- collection.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
- _validateRemoveParentConstraint);
+ //collection.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
+ // _validateRemoveParentConstraint);
+
+ parentColumns [0].Table.Constraints.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
+ _validateRemoveParentConstraint);
+
}
internal override void AddToConstraintCollectionSetup(
ConstraintCollection collection)
{
-
+
//run Ctor rules again
_validateColumns(_parentColumns, _childColumns);
//Make sure we can create this thing
AssertConstraint(); //TODO:if this fails and we created a unique constraint
//we should probably roll it back
-
+ if (collection.Table != Table)
+ throw new InvalidConstraintException("This constraint cannot be added since ForeignKey doesn't belong to table " + RelatedTable.TableName + ".");
}
[MonoTODO]
internal override void AssertConstraint()
{
+
//Constraint only works if both tables are part of the same dataset
//if DataSet ...
[MonoTODO]
internal override void AssertConstraint(DataRow row)
{
-
if (_dataTable == null) return; //???
if (_dataColumns == null) return; //???
-
//Unique?
DataTable tbl = _dataTable;
-
+ bool isValid;
foreach(DataRow compareRow in tbl.Rows)
{
+ isValid = false;
//skip if it is the same row to be validated
if(!row.Equals(compareRow))
{
- if(compareRow.HasVersion (DataRowVersion.Original))
+ //FIXME: should we compare to compareRow[DataRowVersion.Current]?
+ //FIXME: We need to compare to all columns the constraint is set to.
+
+ for (int i = 0; i < _dataColumns.Length; i++)
{
- //FIXME: should we compare to compareRow[DataRowVersion.Current]?
- //FIXME: We need to compare to all columns the constraint is set to.
- if(row[_dataColumns[0], DataRowVersion.Proposed].Equals( compareRow[_dataColumns[0], DataRowVersion.Current]))
+ // if the values in the row are not equal to the values of
+ // the original row from the table we can move to the next row.
+ if(!row[_dataColumns[i]].Equals( compareRow[_dataColumns[i]]))
{
- string ExceptionMessage;
- ExceptionMessage = "Column '" + _dataColumns[0].ColumnName + "' is constrained to be unique.";
- ExceptionMessage += " Value '" + row[_dataColumns[0], DataRowVersion.Proposed].ToString();
- ExceptionMessage += "' is already present.";
-
- throw new ConstraintException (ExceptionMessage);
+ isValid = true;
+ break;
}
-
}
+
+ if (!isValid)
+ throw new ConstraintException(GetErrorMessage(compareRow));
- }
+ }
}
}
+ private string GetErrorMessage(DataRow row)
+ {
+ int i;
+
+ System.Text.StringBuilder sb = new System.Text.StringBuilder(row[_dataColumns[0]].ToString());
+ for (i = 1; i < _dataColumns.Length; i++)
+ sb = sb.Append(", ").Append(row[_dataColumns[i].ColumnName]);
+ string valStr = sb.ToString();
+ sb = new System.Text.StringBuilder(_dataColumns[0].ColumnName);
+ for (i = 1; i < _dataColumns.Length; i++)
+ sb = sb.Append(", ").Append(_dataColumns[i].ColumnName);
+ string colStr = sb.ToString();
+ return "Column '" + colStr + "' is constrained to be unique. Value '" + valStr + "' is already present.";
+ }
+
#endregion // Methods
}
}