base.AddCore (relation);
if (relation.ChildTable.DataSet != this.dataSet || relation.ParentTable.DataSet != this.dataSet)
throw new DataException ();
- List.Add (relation);
+ //List.Add (relation);
relation.SetDataSet (dataSet);
relation.ParentTable.ChildRelations.Add (relation);
relation.ChildTable.ParentRelations.Add (relation);
ForeignKeyConstraint foreignKeyConstraint = null;
- if (relation.createConstraints) {
+ if (relation.createConstraints) \r
+ {
foreignKeyConstraint = new ForeignKeyConstraint (relation.ParentColumns, relation.ChildColumns);
relation.ChildTable.Constraints.Add (foreignKeyConstraint);
- }
- UniqueConstraint uniqueConstraint = null;
- foreach (object o in List) {
- if (o is UniqueConstraint) {
- UniqueConstraint uc = (UniqueConstraint) o;
- if (uc.Columns.Length == relation.ParentColumns.Length) {
- bool allColumnsEqual = true;
- for (int columnCnt = 0; columnCnt < uc.Columns.Length; ++columnCnt) {
- if (uc.Columns[columnCnt] != relation.ParentColumns[columnCnt]) {
- allColumnsEqual = false;
+
+ UniqueConstraint uniqueConstraint = null;
+ ConstraintCollection parentConstrains = relation.ParentTable.Constraints;
+ // find if the unique constraint already exists in the parent table.
+ foreach (Constraint o in parentConstrains) \r
+ {
+ if (o is UniqueConstraint) \r
+ {
+ UniqueConstraint uc = (UniqueConstraint) o;
+ if (uc.Columns.Length == relation.ParentColumns.Length) \r
+ {
+ bool allColumnsEqual = true;
+ for (int columnCnt = 0; columnCnt < uc.Columns.Length; ++columnCnt) \r
+ {
+ if (uc.Columns[columnCnt] != relation.ParentColumns[columnCnt]) \r
+ {
+ allColumnsEqual = false;
+ break;
+ }
+ }
+ if (allColumnsEqual) \r
+ {
+ uniqueConstraint = uc;
break;
}
}
- if (allColumnsEqual) {
- uniqueConstraint = uc;
- break;
- }
}
}
+ // if we did not find the unique constraint in the parent table.
+ // we generate new uniqueconastraint and add it to the parent table.
+ if (uniqueConstraint == null)
+ {
+ uniqueConstraint = new UniqueConstraint(relation.ParentColumns, false);
+ relation.ParentTable.Constraints.Add(uniqueConstraint);
+ }
+ relation.SetParentKeyConstraint (uniqueConstraint);
+ relation.SetChildKeyConstraint (foreignKeyConstraint);
}
- // if we did not find the unique constraint in the parent table.
- // we generate new uniqueconastraint and add it to the parent table.
- if (uniqueConstraint == null)
- {
- uniqueConstraint = new UniqueConstraint(relation.ParentColumns, false);
- relation.ParentTable.Constraints.Add(uniqueConstraint);
- }
- relation.SetParentKeyConstraint (uniqueConstraint);
- relation.SetChildKeyConstraint (foreignKeyConstraint);
}
public override void AddRange (DataRelation[] relations)
public override void Clear ()
{
- base.Clear ();
+ for (int i = 0; i < Count; i++)
+ RemoveCore(this[i]);
+
+ base.Clear();
}
protected override void RemoveCore (DataRelation relation)
{
- base.RemoveCore (relation);
relation.SetDataSet (null);
relation.ParentTable.ChildRelations.Remove (relation);
relation.ChildTable.ParentRelations.Remove (relation);
- ForeignKeyConstraint foreignKeyConstraint = null;
relation.SetParentKeyConstraint (null);
relation.SetChildKeyConstraint (null);
}
public void RemoveAt (int index)
{
- List.RemoveAt (index);
+ Remove(this[index]);
}
[MonoTODO]
_table = builder.Table;
original = null;
- current = new object[_table.Columns.Count];
- // initialize to DBNull.Value
- for (int c = 0; c < _table.Columns.Count; c++) {
- current[c] = DBNull.Value;
- }
+
proposed = new object[_table.Columns.Count];
- Array.Copy (current, proposed, _table.Columns.Count);
-
+ for (int c = 0; c < _table.Columns.Count; c++)
+ {
+ proposed[c] = DBNull.Value;
+ }
+
columnErrors = new string[_table.Columns.Count];
rowError = String.Empty;
public bool HasErrors {
[MonoTODO]
get {
- throw new NotImplementedException ();
+ if (RowError != string.Empty)
+ return true;
+
+ for (int i= 0; i < columnErrors.Length; i++){
+ if (columnErrors[i] != null && columnErrors[i] != string.Empty)
+ return true;
+ }
+
+ return false;
}
}
/// Gets or sets the data stored in specified DataColumn
/// </summary>
public object this[DataColumn column] {
- get { return this[column, DataRowVersion.Default]; }
+
+ get {
+ return this[column, DataRowVersion.Default];}
set {
int columnIndex = _table.Columns.IndexOf (column);
if (columnIndex == -1)
DataColumn column = _table.Columns[columnIndex];
_table.ChangingDataColumn (this, column, value);
+
bool orginalEditing = editing;
if (!orginalEditing) BeginEdit ();
object v = SetColumnValue (value, columnIndex);
[MonoTODO]
public void Delete ()
{
+ _table.DeletingDataRow(this, DataRowAction.Delete);
switch (rowState) {
case DataRowState.Added:
Table.Rows.Remove (this);
case DataRowState.Deleted:
throw new DeletedRowInaccessibleException ();
default:
- //TODO: Events, Constraints
+ // check what to do with child rows
+ CheckChildRows(DataRowAction.Delete);
rowState = DataRowState.Deleted;
break;
}
+ _table.DeletedDataRow(this, DataRowAction.Delete);
+ }
+
+ // check the child rows of this row before deleting the row.
+ private void CheckChildRows(DataRowAction action)
+ {
+
+ // in this method we find the row that this row is in a reltion with them.
+ // in shortly we find all child rows of this row.
+ // then we function according to the DeleteRule of the foriegnkey.
+
+
+ // 1. find if this row is attached to dataset.
+ // 2. find if EnforceConstraints is true.
+ // 3. find if there are any constraint on the table that the row is in.
+ if (_table.DataSet != null && _table.DataSet.EnforceConstraints && _table.Constraints.Count > 0)
+ {
+ // loop on all relations of the dataset.
+ DataRelationCollection relCollection = _table.DataSet.Relations;
+ for (int i = 0; i < relCollection.Count; i++)
+ {
+ DataRelation rel = relCollection[i];
+ // we want only relations that their parent table is the table this row is in.
+ // that is because we interesting only in relations that the row is a parent of
+ // other rows.
+ if (rel.ParentTable == _table)
+ {
+ Rule rule;
+ if (action == DataRowAction.Delete)
+ rule = rel.ChildKeyConstraint.DeleteRule;
+ else
+ rule = rel.ChildKeyConstraint.UpdateRule;
+
+ DataRow[] childRows = GetChildRows(rel);
+ switch (rule)
+ {
+ case Rule.Cascade: // delete or change all relted rows.
+ if (childRows != null)
+ {
+ for (int j = 0; j < childRows.Length; j++)
+ {
+ // if action is delete we delte all child rows
+ if (action == DataRowAction.Delete)
+ childRows[j].Delete();
+ // if action is change we change the values in the child row
+ else if (action == DataRowAction.Change)
+ {
+ // change only the values in the key columns
+ // set the childcolumn value to the new parent row value
+ for (int k = 0; k < rel.ChildColumns.Length; k++)
+ childRows[j][rel.ChildColumns[k]] = this[rel.ParentColumns[k], DataRowVersion.Proposed];
+ }
+ }
+ }
+ break;
+ case Rule.None: // throw an exception if there are any child rows.
+ if (childRows != null)
+ {
+ string changeStr = "Cannot change this row because constraints are enforced on relation " + rel.RelationName +", and changing this row will strand child rows.";
+ string delStr = "Cannot delete this row because constraints are enforced on relation " + rel.RelationName +", and deleting this row will strand child rows.";
+ string message = action == DataRowAction.Delete ? delStr : changeStr;
+ throw new InvalidConstraintException(message);
+ }
+ break;
+ case Rule.SetDefault: // set the values in the child rows to the defult value of the columns.
+ if (childRows != null)
+ {
+ for (int j = 0; j < childRows.Length; j++)
+ {
+ DataRow child = childRows[j];
+ //set only the key columns to default
+ for (int k = 0; k < rel.ChildColumns.Length; k++)
+ child[rel.ChildColumns[k]] = rel.ChildColumns[k].DefaultValue;
+ }
+ }
+ break;
+ case Rule.SetNull: // set the values in the child row to null.
+ if (childRows != null)
+ {
+ for (int j = 0; j < childRows.Length; j++)
+ {
+ DataRow child = childRows[j];
+ // set only the key columns to DBNull
+ for (int k = 0; k < rel.ChildColumns.Length; k++)
+ child.SetNull(rel.ChildColumns[k]);
+ }
+ }
+ break;
+ }
+
+ }
+ }
+ }
}
/// <summary>
return;
if (HasVersion (DataRowVersion.Proposed))
{
+ _table.ChangingDataRow(this, DataRowAction.Change);
if (rowState == DataRowState.Unchanged)
rowState = DataRowState.Modified;
//Calling next method validates UniqueConstraints
//and ForeignKeys.
_table.Rows.ValidateDataRowInternal(this);
+ // check all child rows.
+ CheckChildRows(DataRowAction.Change);
current = proposed;
proposed = null;
+ _table.ChangedDataRow(this, DataRowAction.Change);
}
}
if (columnIndex < 0 || columnIndex >= columnErrors.Length)
throw new IndexOutOfRangeException ();
- return columnErrors[columnIndex];
+ string retVal = columnErrors[columnIndex];
+ if (retVal == null)
+ retVal = string.Empty;
+ return retVal;
}
/// <summary>
for (int i = 0; i < columnErrors.Length; i += 1)
{
- if (columnErrors[i] != String.Empty)
+ if (columnErrors[i] != null && columnErrors[i] != String.Empty)
dataColumns.Add (_table.Columns[i]);
}
- return (DataColumn[])(dataColumns.ToArray ());
+ return (DataColumn[])(dataColumns.ToArray (typeof(DataColumn)));
}
/// <summary>
switch (version)
{
case DataRowVersion.Default:
+ if (rowState == DataRowState.Deleted)
+ return false;
+ if (rowState == DataRowState.Detached)
+ return proposed != null;
return true;
case DataRowVersion.Proposed:
+ if (rowState == DataRowState.Deleted)
+ return false;
return (proposed != null);
case DataRowVersion.Current:
+ if (rowState == DataRowState.Deleted || rowState == DataRowState.Detached)
+ return false;
return (current != null);
case DataRowVersion.Original:
+ if (rowState == DataRowState.Detached)
+ return false;
return (original != null);
}
return false;
//Copy all values of this DataaRow to the row parameter.
internal void CopyValuesToRow(DataRow row)
{
+
if (row == null)
throw new ArgumentNullException("row");
if (row == this)
DataColumnCollection columns = Table.Columns;
for(int i = 0; i < columns.Count; i++){
+
string columnName = columns[i].ColumnName;
int index = row.Table.Columns.IndexOf(columnName);
- //if a column withe the same name exists in bote rows copy the values
+ //if a column with the same name exists in both rows copy the values
if(index != -1) {
if (HasVersion(DataRowVersion.Original))
{
row.proposed = new object[row.Table.Columns.Count];
row.proposed[index] = row.SetColumnValue(proposed[i], index);
}
+
+ //Saving the current value as the column value
+ row[index] = row.current[index];
+
}
}
if (args.Action == System.ComponentModel.CollectionChangeAction.Add)
{
- object[] tmp = new object[current.Length + 1];
- Array.Copy (current, tmp, current.Length);
- tmp[tmp.Length - 1] = DBNull.Value;
- current = tmp;
-
+ object[] tmp;
+ if (current != null)
+ {
+ tmp = new object[current.Length + 1];
+ Array.Copy (current, tmp, current.Length);
+ tmp[tmp.Length - 1] = DBNull.Value;
+ current = tmp;
+ }
if (proposed != null)
{
tmp = new object[proposed.Length + 1];
Array.Copy (proposed, tmp, proposed.Length);
+ tmp[tmp.Length - 1] = DBNull.Value;
proposed = tmp;
}
if(original != null)
{
tmp = new object[original.Length + 1];
Array.Copy (original, tmp, original.Length);
+ tmp[tmp.Length - 1] = DBNull.Value;
original = tmp;
}
foreach (DataRow row in this) {
- object primValue = row [primColumnName];
- if (key == null) {
- if (primValue == null)
- return row;
- else
- continue;
- }
+ if (row.RowState != DataRowState.Deleted)
+ {
+ object primValue = row [primColumnName];
+ if (key == null) \r
+ {
+ if (primValue == null)
+ return row;
+ else
+ continue;
+ }
- newKey = Convert.ChangeType (key, Type.GetTypeCode(primValue.GetType ()));
+ newKey = Convert.ChangeType (key, Type.GetTypeCode(primValue.GetType ()));
- if (primValue.Equals (newKey))
- return row;
+ if (primValue.Equals (newKey))
+ return row;
+ }
}
// FIXME: is the correct value null?
foreach (DataRow row in this) {
- bool eq = true;
- for (int i = 0; i < keys.Length; i++) {
+ if (row.RowState != DataRowState.Deleted)
+ {
+ bool eq = true;
+ for (int i = 0; i < keys.Length; i++) \r
+ {
- object primValue = row [primColumnNames [i]];
- object keyValue = keys [i];
- if (keyValue == null) {
- if (primValue == null)
- return row;
- else
- continue;
- }
+ object primValue = row [primColumnNames [i]];
+ object keyValue = keys [i];
+ if (keyValue == null) \r
+ {
+ if (primValue == null)
+ return row;
+ else
+ continue;
+ }
- newKey = Convert.ChangeType (keyValue, Type.GetTypeCode(primValue.GetType ()));
+ newKey = Convert.ChangeType (keyValue, Type.GetTypeCode(primValue.GetType ()));
- if (!primValue.Equals (newKey)) {
- eq = false;
- break;
- }
- }
+ if (!primValue.Equals (newKey)) \r
+ {
+ eq = false;
+ break;
+ }
+ }
- if (eq)
- return row;
+ if (eq)
+ return row;
+ }
}
// FIXME: is the correct value null?
/// </summary>
public void Remove (DataRow row)
{
- // FIXME: This is the way the MS.NET handles this kind of situation. Could be better, but what can you do.
- if (row == null || list.IndexOf (row) == -1)
+ if (row == null)
throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
-
- list.Remove (row);
- row.DetachRow ();
- table.DeletedDataRow (row, DataRowAction.Delete);
+ int index = list.IndexOf(row);
+ if (index < 0)
+ throw new IndexOutOfRangeException ("The given datarow is not in the current DataRowCollection.");
+ RemoveAt(index);
}
/// <summary>
throw new IndexOutOfRangeException ("There is no row at position " + index + ".");
DataRow row = (DataRow)list [index];
- list.RemoveAt (index);
+ if (row.RowState != DataRowState.Deleted && row.RowState != DataRowState.Added)
+ row.Delete();
+ list.RemoveAt (index);
+ row.DetachRow();
table.DeletedDataRow (row, DataRowAction.Delete);
}
public bool HasErrors {
[MonoTODO]
get {
- throw new NotImplementedException ();
+ for (int i = 0; i < Tables.Count; i++)
+ {
+ if (Tables[i].HasErrors)
+ return true;
+ }
+ return false;
}
}
foreach (DataTable Table in Tables) {
Copy.Tables.Add (Table.Clone ());
- }
+ }
+
+ //Copy Relationships between tables after existance of tables
+ //and setting properties correctly
+ CopyRelations(Copy);
return Copy;
}
Copy.Tables.Add (Table.Copy ());
}
+ //Copy Relationships between tables after existance of tables
+ //and setting properties correctly
+ CopyRelations(Copy);
+
return Copy;
}
//Copy.HasErrors
//Copy.Locale = Locale;
Copy.Namespace = Namespace;
- Copy.Prefix = Prefix;
- //Copy.Relations = Relations;
+ Copy.Prefix = Prefix;
//Copy.Site = Site;
}
+
+
+ private void CopyRelations (DataSet Copy)
+ {
+
+ //Creation of the relation contains some of the properties, and the constructor\r
+ //demands these values. instead changing the DataRelation constructor and behaviour the\r
+ //parameters are pre-configured and sent to the most general constructor
+
+ foreach (DataRelation MyRelation in this.Relations)\r
+ {\r
+ string pTable = MyRelation.ParentTable.TableName;\r
+ string cTable = MyRelation.ChildTable.TableName;\r
+ DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length]; \r
+ DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];\r
+ int i = 0;\r
+ foreach(DataColumn DC in MyRelation.ParentColumns)\r
+ {\r
+ P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];\r
+ i++;\r
+ }\r
+\r
+ i = 0;\r
+\r
+ foreach(DataColumn DC in MyRelation.ChildColumns)\r
+ {\r
+ C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];\r
+ i++;\r
+ }\r
+ \r
+\r
+ DataRelation cRel = new DataRelation(MyRelation.RelationName,P_DC,C_DC);\r
+ //cRel.ChildColumns = MyRelation.ChildColumns;\r
+ //cRel.ChildTable = MyRelation.ChildTable;\r
+ //cRel.ExtendedProperties = cRel.ExtendedProperties; \r
+ //cRel.Nested = MyRelation.Nested;\r
+ //cRel.ParentColumns = MyRelation.ParentColumns;\r
+ //cRel.ParentTable = MyRelation.ParentTable;\r
+ \r
+ Copy.Relations.Add(cRel);\r
+ }
+ }
+
+
+
public DataSet GetChanges()
{
public virtual void Reset()
{
- throw new NotImplementedException ();
+ IEnumerator constraintEnumerator;
+ // first we remove all ForeignKeyConstraints (if we will not do that
+ // we will get an exception when clearing the tables).
+ for (int i = 0; i < Tables.Count; i++)
+ {
+ ConstraintCollection cc = Tables[i].Constraints;
+ for (int j = 0; j < cc.Count; j++)
+ {
+ if (cc[j] is ForeignKeyConstraint)
+ cc.Remove(cc[j]);
+ }
+ }
+
+ Clear();
+ Relations.Clear();
+ Tables.Clear();
}
public void WriteXml(Stream stream)
_primaryKey = null;
_site = null;
_rows = new DataRowCollection (this);
- _locale = CultureInfo.CurrentCulture;
-
+
//LAMESPEC: spec says 25 impl does 50
_minimumCapacity = 50;
OnRowDeleted (e);
}
+ internal void DeletingDataRow (DataRow dr, DataRowAction action)
+ {
+ DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
+ OnRowDeleting(e);
+ }
+
internal void ChangedDataRow (DataRow dr, DataRowAction action)
{
DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
OnRowChanged (e);
}
+ internal void ChangingDataRow (DataRow dr, DataRowAction action)
+ {
+ DataRowChangeEventArgs e = new DataRowChangeEventArgs (dr, action);
+ OnRowChanging (e);
+ }
+
/// <summary>
/// Gets the collection of child relations for this DataTable.
/// </summary>
[Browsable (false)]
[DataSysDescription ("Returns whether the table has errors.")]
public bool HasErrors {
- get { return _hasErrors; }
+ get {
+ // we can not use the _hasError flag because we do not know when to turn it off!
+ for (int i = 0; i < _rows.Count; i++)
+ {
+ if (_rows[i].HasErrors)
+ return true;
+ }
+ return false;
+ }
}
/// <summary>
/// </summary>
[DataSysDescription ("Indicates a locale under which to compare strings within the table.")]
public CultureInfo Locale {
- get { return _locale; }
- set { _locale = value; }
+ get {
+ // if the locale is null, we check for the DataSet locale
+ // and if the DataSet is null we return the current culture.
+ // this way if DataSet locale is changed, only if there is no locale for
+ // the DataTable it influece the Locale get;
+ if (_locale != null)
+ return _locale;
+ if (DataSet != null)
+ return DataSet.Locale;
+ return CultureInfo.CurrentCulture;
+ }
+ set {
+ if (_locale == null || !_locale.Equals(value))
+ _locale = value;
+ }
}
/// <summary>
{
//FIXME: Do we need to validate anything here or
//try to catch any errors to deal with them?
-
- foreach(DataRow myRow in _rows) {
+
+ // we do not use foreach because if one of the rows is in Delete state
+ // it will be romeved from Rows and we get an exception.
+ DataRow myRow;
+ for (int i = 0; i < Rows.Count; )
+ {
+ myRow = Rows[i];
myRow.AcceptChanges();
+
+ // if the row state is Detached it meens that it was removed from row list (Rows)
+ // so we should not increase 'i'.
+ if (myRow.RowState != DataRowState.Detached)
+ i++;
}
}
// TODO: thow an exception if any rows that
// have enforced child relations
// that would result in child rows being orphaned
+ // now we check if any ForeignKeyConstraint is referncing 'table'.
+ if (DataSet != null)
+ {
+ IEnumerator tableEnumerator = 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 = constraintEnumerator.Current;
+ // we only check ForeignKeyConstraint
+ if (o is ForeignKeyConstraint)
+ {
+ ForeignKeyConstraint fc = (ForeignKeyConstraint) o;
+ if(fc.RelatedTable == this && fc.Table.Rows.Count > 0)
+ throw new InvalidConstraintException("Cannot clear table " + fc.RelatedTable + " because ForeignKeyConstraint " + fc.ConstraintName + " enforces constraints and there are child rows in " + fc.Table);
+ }
+ }
+ }
+ }
+
// TODO: throw a NotSupportedException if the DataTable is part
// of a DataSet that is binded to an XmlDataDocument
-
+
_rows.Clear ();
}
DataTable Copy = new DataTable ();
CopyProperties (Copy);
+ // we can not simply copy the row values (NewRow [C.ColumnName] = Row [C.ColumnName])
+ // because if the row state is deleted we get an exception.
foreach (DataRow Row in Rows) {
DataRow NewRow = Copy.NewRow ();
- NewRow.RowError = Row.RowError;
- foreach (DataColumn C in Copy.Columns) {
- NewRow [C.ColumnName] = Row [C.ColumnName];
- }
Copy.Rows.Add (NewRow);
+ Row.CopyValuesToRow(NewRow);
}
return Copy;
Copy.Namespace = Namespace;
// Copy.ParentRelations
Copy.Prefix = Prefix;
- //Copy.PrimaryKey = PrimaryKey;
Copy.Site = Site;
Copy.TableName = TableName;
Copy.Columns.Add (CopyColumn (Column));
}
+ // add primary key to the copy
+ if (PrimaryKey.Length > 0)
+ {
+ DataColumn[] pColumns = new DataColumn[PrimaryKey.Length];
+ for (int i = 0; i < pColumns.Length; i++)
+ pColumns[i] = Copy.Columns[PrimaryKey[i].ColumnName];
+
+ Copy.PrimaryKey = pColumns;
+ }
+
}
/// <summary>
/// Ends the initialization of a DataTable that is used
[MonoTODO]
public DataTable GetChanges()
{
- //TODO:
- return this;
+ return GetChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
}
/// <summary>
[MonoTODO]
public DataTable GetChanges(DataRowState rowStates)
{
- //TODO:
- return this;
+ DataTable copyTable = null;
+
+ IEnumerator rowEnumerator = Rows.GetEnumerator();
+ while (rowEnumerator.MoveNext()) {
+ DataRow row = (DataRow)rowEnumerator.Current;
+ if (row.IsRowChanged(rowStates)) {
+ if (copyTable == null)
+ copyTable = Clone();
+ DataRow newRow = copyTable.NewRow();
+ copyTable.Rows.Add(newRow);
+ row.CopyValuesToRow(newRow);
+ }
+ }
+
+ return copyTable;
}
/// <summary>
[MonoTODO]
public DataRow[] GetErrors ()
{
- throw new NotImplementedException ();
+ ArrayList errors = new ArrayList();
+ for (int i = 0; i < _rows.Count; i++)
+ {
+ if (_rows[i].HasErrors)
+ errors.Add(_rows[i]);
+ }
+
+ return (DataRow[]) errors.ToArray(typeof(DataRow));
}
/// <summary>
[MonoTODO]
public void ImportRow (DataRow row)
{
+ DataRow newRow = NewRow();
+ Rows.Add(newRow);
+ row.CopyValuesToRow(newRow);
+
}
/// <summary>
if (fAcceptChanges)
row.AcceptChanges ();
}
- else
- throw new NotImplementedException ();
+ else {
+ bool hasPrimaryValues = true;
+ // initiate an array that has the values of the primary keys.\r
+ object[] keyValues = new object[PrimaryKey.Length];\r
+ for (int i = 0; i < keyValues.Length && hasPrimaryValues; i++)\r
+ {\r
+ if(PrimaryKey[i].Ordinal < values.Length)\r
+ keyValues[i] = values[PrimaryKey[i].Ordinal];\r
+ else\r
+ hasPrimaryValues = false;\r
+ }\r
+ \r
+ if (hasPrimaryValues){\r
+ // find the row in the table.\r
+ row = Rows.Find(keyValues);
+ }
+
+ if (row == null)
+ row = Rows.Add (values);
+ else
+ row.ItemArray = values;
+
+ if (fAcceptChanges)
+ row.AcceptChanges ();
+ }
+
return row;
}
[MonoTODO]
public void RejectChanges ()
{
- //foreach(DataRow myRow in _rows)
- //{
for (int i = _rows.Count - 1; i >= 0; i--) {
DataRow row = _rows [i];
if (row.RowState != DataRowState.Unchanged)
[MonoTODO]
public virtual void Reset ()
{
+ Clear();
+ while (ParentRelations.Count > 0)
+ {
+ if (dataSet.Relations.Contains(ParentRelations[ParentRelations.Count - 1].RelationName))
+ dataSet.Relations.Remove(ParentRelations[ParentRelations.Count - 1]);
+ }
+
+ while (ChildRelations.Count > 0)
+ {
+ if (dataSet.Relations.Contains(ChildRelations[ChildRelations.Count - 1].RelationName))
+ dataSet.Relations.Remove(ChildRelations[ChildRelations.Count - 1]);
+ }
+ Constraints.Clear();
+ Columns.Clear();
}
/// <summary>
ArrayList List = new ArrayList ();
foreach (DataRow Row in Rows) {
-
if (Expression.Test (Row))
List.Add (Row);
}
{
//LAMESPEC: spec says concat the two. impl puts a
//plus sign infront of DisplayExpression
- return TableName + " + " + DisplayExpression;
+ string retVal = TableName;
+ if(DisplayExpression != null && DisplayExpression != "")
+ retVal += " + " + DisplayExpression;
+ return retVal;
}
internal void UpdatePrimaryKey ()
{
_isPrimaryKey = __isPrimaryKey;
- if (_isPrimaryKey) {
- foreach (DataColumn Col in _dataColumns)
- Col.SetUnique();
- }
+ foreach (DataColumn Col in _dataColumns)
+ Col.SetUnique();
+
}
internal static void SetAsPrimaryKey(ConstraintCollection collection, UniqueConstraint newPrimaryKey)
DataTable tbl = _dataTable;
//TODO: Investigate other ways of speeding up the validation work below.
- //FIXME: This only works when only one DataColumn has been specified.
//validate no duplicates exists.
//Only validate when there are at least 2 rows
//original.
DataRow[] rows = new DataRow [tbl.Rows.Count];
tbl.Rows.CopyTo (rows, 0);
- ArrayList clonedDataList = new ArrayList (rows);
-
- ArrayList newDataList = new ArrayList();
-
- //copy to array list only the column we are interested in.
- foreach (DataRow row in clonedDataList) {
-
- object colvalue = row[this._dataColumns[0]];
- if (colvalue == DBNull.Value)
- newDataList.Add (null);
- else
- newDataList.Add (colvalue);
- }
- //sort ArrayList and check adjacent values for duplicates.
- newDataList.Sort ();
-
- for (int i = 0 ; i < newDataList.Count - 1 ; i++)
-
- if (newDataList [i] == null) {
- if (newDataList [i+1] == null)
- throw new InvalidConstraintException (String.Format ("Column '{0}' contains non-unique values", this._dataColumns[0]));
- }
- else if (newDataList[i].Equals (newDataList[i+1]))
- throw new InvalidConstraintException (String.Format ("Column '{0}' contains non-unique values", this._dataColumns[0]));
+ Array.Sort(rows, new RowsComparer(this));
+ for (int i = 0 ; i < rows.Length - 1 ; i++)
+ {\r
+ bool match = true;\r
+ // check if the values in the constraints columns are equal\r
+ for (int j = 0; j < _dataColumns.Length; j++)\r
+ {\r
+ if (!rows[i][_dataColumns[j]].Equals(rows[i + 1][_dataColumns[j]]))\r
+ {\r
+ match = false;\r
+ break;\r
+ } \r
+ }\r
+ if (match)\r
+ throw new InvalidConstraintException (String.Format ("Column '{0}' contains non-unique values", this._dataColumns[0]));
+ }
}
DataTable tbl = _dataTable;
bool isValid;
+ object[] rowVals = new object[_dataColumns.Length];
+ for (int i = 0; i < _dataColumns.Length; i++)
+ {
+ if(row.HasVersion(DataRowVersion.Proposed))
+ rowVals[i] = row[_dataColumns[i], DataRowVersion.Proposed];
+ else
+ rowVals[i] = row[_dataColumns[i], DataRowVersion.Current];
+ }
+
foreach(DataRow compareRow in tbl.Rows)
{
- isValid = false;
- //skip if it is the same row to be validated
- if(!row.Equals(compareRow))
+ if (compareRow.RowState != DataRowState.Deleted)
{
- //FIXME: should we compare to compareRow[DataRowVersion.Current]?
- //FIXME: We need to compare to all columns the constraint is set to.
- object rowVal;
- for (int i = 0; i < _dataColumns.Length; i++)
+ isValid = false;
+ //skip if it is the same row to be validated
+ if(!row.Equals(compareRow))
{
- if(row.HasVersion(DataRowVersion.Proposed))
- rowVal = row[_dataColumns[i], DataRowVersion.Proposed];
- else
- rowVal = row[_dataColumns[i], 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(!rowVal.Equals( compareRow[_dataColumns[i]]))
+ //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++)
{
- isValid = true;
- break;
+ // 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(!rowVals[i].Equals( compareRow[_dataColumns[i]]))
+ {
+ isValid = true;
+ break;
+ }
}
- }
- if (!isValid)
- throw new ConstraintException(GetErrorMessage(compareRow));
+ if (!isValid)
+ throw new ConstraintException(GetErrorMessage(compareRow));
+ }
}
}
string colStr = sb.ToString();
return "Column '" + colStr + "' is constrained to be unique. Value '" + valStr + "' is already present.";
}
+
+ // generates a hash key for a given row based on the constraints columns.
+ internal int CalcHashValue(DataRow row)
+ {
+ object o;
+ int retVal = 0;
+ for (int i = 0; i < _dataColumns.Length; i++)
+ {
+ o = row[_dataColumns[i]];
+ if (o != null)
+ retVal += o.GetHashCode();
+ }
+ return retVal;
+ }
#endregion // Methods
+
+ private class RowsComparer : IComparer
+ {
+ private UniqueConstraint _uc;
+
+ public RowsComparer(UniqueConstraint uc)
+ {
+ _uc = uc;
+ }
+
+ public int Compare(object o1, object o2)
+ {
+ DataRow row1 = (DataRow) o1;
+ DataRow row2 = (DataRow) o2;
+ int val1 = _uc.CalcHashValue(row1);
+ int val2 = _uc.CalcHashValue(row2);
+
+ return val1 - val2;
+ }
+ }
}
+
+
}