[DefaultEvent ("RowChanging")]
[DefaultProperty ("TableName")]
[DesignTimeVisible (false)]
+ [EditorAttribute ("Microsoft.VSDesigner.Data.Design.DataTableEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
+ [TypeConverterAttribute("System.ComponentModel.ComponentConverter, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
[Serializable]
public class DataTable : MarshalByValueComponent, IListSource, ISupportInitialize, ISerializable
{
private string _encodedTableName;
internal bool _duringDataLoad;
private bool dataSetPrevEnforceConstraints;
+ private bool dataTablePrevEnforceConstraints;
+ private bool enforceConstraints = true;
private DataRowBuilder _rowBuilder;
private ArrayList _indexes;
[DataSysDescription ("Indicates whether comparing strings within the table is case sensitive.")]
public bool CaseSensitive {
get { return _caseSensitive; }
- set {
+ set {
+ if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
+ throw new ArgumentException ("Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.");
+ }
_virginCaseSensitive = false;
_caseSensitive = value;
}
return CultureInfo.CurrentCulture;
}
set {
+ if (_childRelations.Count > 0 || _parentRelations.Count > 0) {
+ throw new ArgumentException ("Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.");
+ }
if (_locale == null || !_locale.Equals(value))
_locale = value;
}
[DefaultValue ("")]
public string Prefix {
get { return "" + _prefix; }
- set { _prefix = value; }
+ set {
+ // Prefix cannot contain any special characters other than '_' and ':'
+ for (int i = 0; i < value.Length; i++) {
+ if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
+ throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
+ }
+ _prefix = value;
+ }
}
/// <summary>
/// </summary>
[DataCategory ("Data")]
[DataSysDescription ("Indicates the column(s) that represent the primary key for this table.")]
+ [EditorAttribute ("Microsoft.VSDesigner.Data.Design.PrimaryKeyEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
+ [TypeConverterAttribute ("System.Data.PrimaryKeyTypeConverter, System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public DataColumn[] PrimaryKey {
get {
UniqueConstraint uc = UniqueConstraint.GetPrimaryKeyConstraint( Constraints);
return false;
}
}
+
+ private bool EnforceConstraints {
+ get { return enforceConstraints; }
+ set {
+ if (value != enforceConstraints) {
+ if (value) {
+ // first assert all unique constraints
+ foreach (UniqueConstraint uc in this.Constraints.UniqueConstraints)
+ uc.AssertConstraint ();
+ // then assert all foreign keys
+ foreach (ForeignKeyConstraint fk in this.Constraints.ForeignKeyConstraints)
+ fk.AssertConstraint ();
+ }
+ enforceConstraints = value;
+ }
+ }
+ }
public bool RowsExist(Object[] columns, Object[] relatedColumns,DataRow row)
{
this.dataSetPrevEnforceConstraints = this.dataSet.EnforceConstraints;
this.dataSet.EnforceConstraints = false;
}
+ else {
+ //if table does not belong to any data set use EnforceConstraints of the table
+ this.dataTablePrevEnforceConstraints = this.EnforceConstraints;
+ this.EnforceConstraints = false;
+ }
}
return;
}
// have enforced child relations
// that would result in child rows being orphaned
// now we check if any ForeignKeyConstraint is referncing 'table'.
+ if (DataSet._xmlDataDocument != null)
+ throw new NotSupportedException ("Clear function on dataset and datatable is not supported on XmlDataDocument.");
if (DataSet != null)
{
IEnumerator tableEnumerator = DataSet.Tables.GetEnumerator();
}
}
- // TODO: throw a NotSupportedException if the DataTable is part
- // of a DataSet that is binded to an XmlDataDocument
_rows.Clear ();
}
/// Clones the structure of the DataTable, including
/// all DataTable schemas and constraints.
/// </summary>
- [MonoTODO]
public virtual DataTable Clone ()
{
DataTable Copy = new DataTable ();
/// <summary>
/// Copies both the structure and data for this DataTable.
/// </summary>
- [MonoTODO]
public DataTable Copy ()
{
DataTable Copy = new DataTable ();
return Copy;
}
- [MonoTODO]
private void CopyProperties (DataTable Copy)
{
// Copy.DefaultView
// Copy.DesignMode
Copy.DisplayExpression = DisplayExpression;
- // Copy.ExtendedProperties
+ // Cannot copy extended properties directly as the property does not have a set accessor
+ Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
+ ExtendedProperties.Keys.CopyTo (tgtArray, 0);
+ for (int i=0; i < ExtendedProperties.Count; i++)
+ Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
Copy.Locale = Locale;
Copy.MinimumCapacity = MinimumCapacity;
Copy.Namespace = Namespace;
/// Turns on notifications, index maintenance, and
/// constraints after loading data.
/// </summary>
- [MonoTODO]
public void EndLoadData()
{
int i = 0;
if (this._duringDataLoad)
{
- //Returning from loading mode, raising exceptions as usual
- this._duringDataLoad = false;
if (this.dataSet !=null)
{
//Getting back to previous EnforceConstraint state
this.dataSet.EnforceConstraints = this.dataSetPrevEnforceConstraints;
}
+ else {
+ //Getting back to the table's previous EnforceConstraint state
+ this.EnforceConstraints = this.dataTablePrevEnforceConstraints;
+ }
for (i=0 ; i<this.Rows.Count ; i++)
{
if (this.Rows[i]._nullConstraintViolation )
}
}
+ //Returning from loading mode, raising exceptions as usual
+ this._duringDataLoad = false;
}
/// changes made to it since it was loaded or
/// AcceptChanges was last called.
/// </summary>
- [MonoTODO]
public DataTable GetChanges()
{
return GetChanges(DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
/// changes made to it since it was last loaded, or
/// since AcceptChanges was called, filtered by DataRowState.
/// </summary>
- [MonoTODO]
public DataTable GetChanges(DataRowState rowStates)
{
DataTable copyTable = null;
IEnumerator rowEnumerator = Rows.GetEnumerator();
while (rowEnumerator.MoveNext()) {
DataRow row = (DataRow)rowEnumerator.Current;
+ // The spec says relationship constraints may cause Unchanged parent rows to be included but
+ // MS .NET 1.1 does not include Unchanged rows even if their child rows are changed.
if (row.IsRowChanged(rowStates)) {
if (copyTable == null)
copyTable = Clone();
DataRow newRow = copyTable.NewRow();
- copyTable.Rows.Add(newRow);
row.CopyValuesToRow(newRow);
+ copyTable.Rows.Add (newRow);
}
}
/// <summary>
/// Gets an array of DataRow objects that contain errors.
/// </summary>
- [MonoTODO]
public DataRow[] GetErrors ()
{
ArrayList errors = new ArrayList();
/// Copies a DataRow into a DataTable, preserving any
/// property settings, as well as original and current values.
/// </summary>
- [MonoTODO]
public void ImportRow (DataRow row)
{
DataRow newRow = NewRow();
/// Finds and updates a specific row. If no matching row
/// is found, a new row is created using the given values.
/// </summary>
- [MonoTODO]
public DataRow LoadDataRow (object[] values, bool fAcceptChanges)
{
DataRow row = null;
/// table since it was loaded, or the last time AcceptChanges
/// was called.
/// </summary>
- [MonoTODO]
public void RejectChanges ()
{
for (int i = _rows.Count - 1; i >= 0; i--) {
/// <summary>
/// Resets the DataTable to its original state.
/// </summary>
- [MonoTODO]
public virtual void Reset ()
{
Clear();
using NUnit.Framework;
using System;
using System.Data;
+using System.Globalization;
namespace MonoTests.System.Data
{
AssertEquals ("test#16", "Column2", dt.PrimaryKey [1].ColumnName);
}
+
+ [Test]
+ public void PropertyExceptions ()
+ {
+ DataSet set = new DataSet ();
+ DataTable table = new DataTable ();
+ DataTable table1 = new DataTable ();
+ set.Tables.Add (table);
+ set.Tables.Add (table1);
+
+ DataColumn col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table.Columns.Add (col);
+ UniqueConstraint uc = new UniqueConstraint ("UK1", table.Columns[0] );
+ table.Constraints.Add (uc);
+ table.CaseSensitive = false;
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table.Columns.Add (col);
+
+ col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table1.Columns.Add (col);
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table1.Columns.Add (col);
+
+ DataRelation dr = new DataRelation ("DR", table.Columns[0], table1.Columns[0]);
+ set.Relations.Add (dr);
+
+ try {
+ table.CaseSensitive = true;
+ table1.CaseSensitive = true;
+ Fail ("#A01");
+ }
+ catch (Exception e) {
+ if (e.GetType () != typeof (AssertionException))
+ AssertEquals ("#A02", "Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.",e.Message);
+ else
+ Console.WriteLine (e);
+ }
+ try {
+ CultureInfo cultureInfo = new CultureInfo ("en-gb");
+ table.Locale = cultureInfo;
+ table1.Locale = cultureInfo;
+ Fail ("#A03");
+ }
+ catch (Exception e) {
+ if (e.GetType () != typeof (AssertionException))
+ AssertEquals ("#A04", "Cannot change CaseSensitive or Locale property. This change would lead to at least one DataRelation or Constraint to have different Locale or CaseSensitive settings between its related tables.",e.Message);
+ else
+ Console.WriteLine (e);
+ }
+ try {
+ table.Prefix = "Prefix#1";
+ Fail ("#A05");
+ }
+ catch (Exception e){
+ if (e.GetType () != typeof (AssertionException))
+ AssertEquals ("#A06", "Prefix 'Prefix#1' is not valid, because it contains special characters.",e.Message);
+ else
+ Console.WriteLine (e);
+
+ }
+ }
+
+ [Test]
+ public void GetErrors ()
+ {
+ DataTable table = new DataTable ();
+
+ DataColumn col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table.Columns.Add (col);
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table.Columns.Add (col);
+
+ DataRow row = table.NewRow ();
+ row ["Id"] = 147;
+ row ["name"] = "Abc";
+ row.RowError = "Error#1";
+ table.Rows.Add (row);
+ AssertEquals ("#A01", 1, table.GetErrors ().Length);
+ AssertEquals ("#A02", "Error#1", (table.GetErrors ())[0].RowError);
+ }
+ [Test]
+ public void CloneCopyTest ()
+ {
+ DataTable table = new DataTable ();
+ table.TableName = "Table#1";
+ DataTable table1 = new DataTable ();
+ table1.TableName = "Table#2";
+
+ table.AcceptChanges ();
+
+ DataSet set = new DataSet ("Data Set#1");
+ set.DataSetName = "Dataset#1";
+ set.Tables.Add (table);
+ set.Tables.Add (table1);
+
+ DataColumn col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table.Columns.Add (col);
+ UniqueConstraint uc = new UniqueConstraint ("UK1", table.Columns[0] );
+ table.Constraints.Add (uc);
+
+ col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table1.Columns.Add (col);
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table.Columns.Add (col);
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table1.Columns.Add (col);
+ DataRow row = table.NewRow ();
+ row ["Id"] = 147;
+ row ["name"] = "Abc";
+ row.RowError = "Error#1";
+ table.Rows.Add (row);
+
+ row = table.NewRow ();
+ row ["Id"] = 47;
+ row ["name"] = "Efg";
+ table.Rows.Add (row);
+ table.AcceptChanges ();
+
+ table.CaseSensitive = true;
+ table1.CaseSensitive = true;
+ table.MinimumCapacity = 100;
+ table.Prefix = "PrefixNo:1";
+ table.Namespace = "Namespace#1";
+ table.DisplayExpression = "Id / Name + (Id * Id)";
+ DataColumn[] colArray = {table.Columns[0]};
+ table.PrimaryKey = colArray;
+ table.ExtendedProperties.Add ("TimeStamp", DateTime.Now);
+ CultureInfo cultureInfo = new CultureInfo ("en-gb");
+ table.Locale = cultureInfo;
+
+ row = table1.NewRow ();
+ row ["Name"] = "Abc";
+ row ["Id"] = 147;
+ table1.Rows.Add (row);
+
+ row = table1.NewRow ();
+ row ["Id"] = 47;
+ row ["Name"] = "Efg";
+ table1.Rows.Add (row);
+
+ DataRelation dr = new DataRelation ("DR", table.Columns[0], table1.Columns[0]);
+ set.Relations.Add (dr);
+
+ //Testing properties of clone
+ DataTable cloneTable = table.Clone ();
+ AssertEquals ("#A01",true ,cloneTable.CaseSensitive);
+ AssertEquals ("#A02", 0 , cloneTable.ChildRelations.Count);
+ AssertEquals ("#A03", 0 , cloneTable.ParentRelations.Count);
+ AssertEquals ("#A04", 2, cloneTable.Columns.Count);
+ AssertEquals ("#A05", 1, cloneTable.Constraints.Count);
+ AssertEquals ("#A06", "Id / Name + (Id * Id)", cloneTable.DisplayExpression);
+ AssertEquals ("#A07", 1 ,cloneTable.ExtendedProperties.Count);
+ AssertEquals ("#A08", false ,cloneTable.HasErrors);
+ AssertEquals ("#A09", 2057, cloneTable.Locale.LCID);
+ AssertEquals ("#A10", 100, cloneTable.MinimumCapacity);
+ AssertEquals ("#A11","Namespace#1", cloneTable.Namespace);
+ AssertEquals ("#A12", "PrefixNo:1",cloneTable.Prefix);
+ AssertEquals ("#A13", "Id", cloneTable.PrimaryKey[0].ColumnName);
+ AssertEquals ("#A14",0 , cloneTable.Rows.Count );
+ AssertEquals ("#A15", "Table#1", cloneTable.TableName);
+
+ //Testing properties of copy
+ DataTable copyTable = table.Copy ();
+ AssertEquals ("#A16",true ,copyTable.CaseSensitive);
+ AssertEquals ("#A17", 0 , copyTable.ChildRelations.Count);
+ AssertEquals ("#A18", 0 , copyTable.ParentRelations.Count);
+ AssertEquals ("#A19", 2, copyTable.Columns.Count);
+ AssertEquals ("#A20", 1, copyTable.Constraints.Count);
+ AssertEquals ("#A21", "Id / Name + (Id * Id)", copyTable.DisplayExpression);
+ AssertEquals ("#A22", 1 ,copyTable.ExtendedProperties.Count);
+ AssertEquals ("#A23", true ,copyTable.HasErrors);
+ AssertEquals ("#A24", 2057, copyTable.Locale.LCID);
+ AssertEquals ("#A25", 100, copyTable.MinimumCapacity);
+ AssertEquals ("#A26","Namespace#1", copyTable.Namespace);
+ AssertEquals ("#A27", "PrefixNo:1",copyTable.Prefix);
+ AssertEquals ("#A28", "Id", copyTable.PrimaryKey[0].ColumnName);
+ AssertEquals ("#A29", 2 , copyTable.Rows.Count );
+ AssertEquals ("#A30", "Table#1", copyTable.TableName);
+ }
+
+ [Test]
+ public void LoadDataException ()
+ {
+ DataTable table = new DataTable ();
+ DataColumn col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ col.DefaultValue = 47;
+ table.Columns.Add (col);
+ UniqueConstraint uc = new UniqueConstraint ("UK1", table.Columns[0] );
+ table.Constraints.Add (uc);
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ col.DefaultValue = "Hello";
+ table.Columns.Add (col);
+
+ table.BeginLoadData();
+ object[] row = {147, "Abc"};
+ DataRow newRow = table.LoadDataRow (row, true);
+
+ object[] row1 = {147, "Efg"};
+ DataRow newRow1 = table.LoadDataRow (row1, true);
+
+ object[] row2 = {143, "Hij"};
+ DataRow newRow2 = table.LoadDataRow (row2, true);
+
+ try {
+ table.EndLoadData ();
+ Fail ("#A01");
+ }
+ catch (Exception e) {
+ if (e.GetType () != typeof (AssertionException))
+ AssertEquals ("#A02", "Column 'Id' contains non-unique values",e.Message);
+ else
+ Console.WriteLine (e);
+
+ }
+ }
+ [Test]
+ public void Changes () //To test GetChanges and RejectChanges
+ {
+ DataTable table = new DataTable ();
+
+ DataColumn col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table.Columns.Add (col);
+ UniqueConstraint uc = new UniqueConstraint ("UK1", table.Columns[0] );
+ table.Constraints.Add (uc);
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table.Columns.Add (col);
+
+ DataRow row = table.NewRow ();
+ row ["Id"] = 147;
+ row ["name"] = "Abc";
+ table.Rows.Add (row);
+ table.AcceptChanges ();
+
+ row = table.NewRow ();
+ row ["Id"] = 47;
+ row ["name"] = "Efg";
+ table.Rows.Add (row);
+
+ //Testing GetChanges
+ DataTable changesTable = table.GetChanges ();
+ AssertEquals ("#A01", 1 ,changesTable.Rows.Count);
+ AssertEquals ("#A02","Efg" ,changesTable.Rows[0]["Name"]);
+ table.AcceptChanges ();
+ changesTable = table.GetChanges ();
+ try {
+ int cnt = changesTable.Rows.Count;
+ }
+ catch(Exception e) {
+ if (e.GetType () != typeof (AssertionException))
+ AssertEquals ("#A03",typeof(NullReferenceException) ,e.GetType ());
+ else
+ Console.WriteLine (e);
+ }
+
+ //Testing RejectChanges
+ row = table.NewRow ();
+ row ["Id"] = 247;
+ row ["name"] = "Hij";
+ table.Rows.Add (row);
+
+ (table.Rows [0])["Name"] = "AaBbCc";
+ table.RejectChanges ();
+ AssertEquals ("#A03", "Abc" , (table.Rows [0]) ["Name"]);
+ AssertEquals ("#A04", 2, table.Rows.Count);
+ }
+ [Test]
+ public void ImportRow ()
+ {
+ DataTable table = new DataTable ();
+ DataColumn col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table.Columns.Add (col);
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table.Columns.Add (col);
+
+ DataRow row = table.NewRow ();
+ row ["Id"] = 147;
+ row ["name"] = "Abc";
+ table.Rows.Add (row);
+ table.AcceptChanges ();
+
+ row = table.NewRow ();
+ row ["Id"] = 47;
+ row ["name"] = "Efg";
+ table.Rows.Add (row);
+
+ (table.Rows [0]) ["Name"] = "AaBbCc";
+
+ table.ImportRow (table.Rows [0]);
+ table.ImportRow (table.Rows [1]);
+
+ AssertEquals ("#A01", 147, table.Rows [2]["Id"]);
+ AssertEquals ("#A02", 47, table.Rows [3]["Id"]);
+ AssertEquals ("#A03", DataRowState.Modified, table.Rows [2].RowState);
+ AssertEquals ("#A04", DataRowState.Added, table.Rows [3].RowState);
+ }
+ [Test]
+ public void ClearReset () //To test Clear and Reset methods
+ {
+ DataTable table = new DataTable ();
+ DataTable table1 = new DataTable ();
+
+ DataSet set = new DataSet ();
+ set.Tables.Add (table);
+ set.Tables.Add (table1);
+
+ DataColumn col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table.Columns.Add (col);
+ UniqueConstraint uc = new UniqueConstraint ("UK1", table.Columns[0] );
+ table.Constraints.Add (uc);
+ table.CaseSensitive = false;
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table.Columns.Add (col);
+
+ col = new DataColumn ();
+ col.ColumnName = "Id";
+ col.DataType = System.Type.GetType ("System.Int32");
+ table1.Columns.Add (col);
+
+ col = new DataColumn ();
+ col.ColumnName = "Name";
+ col.DataType = System.Type.GetType ("System.String");
+ table1.Columns.Add (col);
+
+ DataRelation dr = new DataRelation ("DR", table.Columns[0], table1.Columns[0]);
+ set.Relations.Add (dr);
+
+ DataRow row = table.NewRow ();
+ row ["Id"] = 147;
+ row ["name"] = "Roopa";
+ table.Rows.Add (row);
+
+ row = table.NewRow ();
+ row ["Id"] = 47;
+ row ["Name"] = "roopa";
+ table.Rows.Add (row);
+
+ try {
+ table.Reset ();
+ Fail ("#A01");
+ }
+ catch (Exception e) {
+ if (e.GetType () != typeof (AssertionException)) {
+ AssertEquals ("#A02", "Cannot clear table Parent because ForeignKeyConstraint DR enforces Child.", e.Message);
+ }
+ }
+ try {
+ table.Clear ();
+ Fail ("#A03");
+ }
+ catch (Exception e) {
+ if (e.GetType () != typeof (AssertionException)) {
+ AssertEquals ("#A04", "Cannot clear table Parent because ForeignKeyConstraint DR enforces Child.", e.Message);
+ }
+ }
+ table1.Reset ();
+ AssertEquals ("#A05", 0, table1.Rows.Count);
+ AssertEquals ("#A06", 0, table1.Constraints.Count);
+ AssertEquals ("#A07", 0, table1.ParentRelations.Count);
+
+ table.Clear ();
+ AssertEquals ("#A08", 0, table.Rows.Count);
+ AssertEquals ("#A09", 1, table.Constraints.Count);
+ AssertEquals ("#A05", 0, table.ChildRelations.Count);
+ }
}
}