Index: System.Data/DataRelation.cs
===================================================================
RCS file: /mono/mcs/class/System.Data/System.Data/DataRelation.cs,v
retrieving revision 1.2
diff -u -r1.2 DataRelation.cs
--- System.Data/DataRelation.cs	12 Nov 2002 01:41:04 -0000	1.2
+++ System.Data/DataRelation.cs	17 Feb 2003 17:07:29 -0000
@@ -3,6 +3,7 @@
 //
 // Author:
 //   Daniel Morgan <danmorg@sc.rr.com>
+//   Alan Tam Siu Lung <Tam@SiuLung.com>
 //
 // (C) 2002 Daniel Morgan
 // (C) 2002 Ximian, Inc.
@@ -21,32 +22,53 @@
 	[DefaultProperty ("RelationName")]
 	[Serializable]
 	public class DataRelation {
+		private DataSet dataSet;
+		private string relationName;
+		private UniqueConstraint parentKeyConstraint;
+		private ForeignKeyConstraint childKeyConstraint;
+		private DataColumn[] parentColumns;
+		private DataColumn[] childColumns;
+		private bool nested;
+		internal bool createConstraints;
 
 		#region Constructors
 
-		[MonoTODO]
 		public DataRelation (string relationName, DataColumn parentColumn, DataColumn childColumn) 
+		: this(relationName, parentColumn, childColumn, true)
 		{
-			throw new NotImplementedException ();
 		}
 
-		[MonoTODO]
 		public DataRelation (string relationName, DataColumn[] parentColumns, DataColumn[] childColumns) 
+		: this(relationName, parentColumns, childColumns, true)
 		{
-
-			throw new NotImplementedException ();
 		}
 
-		[MonoTODO]
-		public DataRelation (string relationName, DataColumn parentColumn, DataColumn childColumn, bool createConstraints)
+		public DataRelation (string relationName, DataColumn parentColumn, DataColumn childColumn, bool createConstraints)
+		: this(relationName, new DataColumn[] { parentColumn }, new DataColumn[] { childColumn }, createConstraints)
 		{
-			throw new NotImplementedException ();
 		}
 
-		[MonoTODO]
 		public DataRelation (string relationName, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints) 
 		{
-			throw new NotImplementedException ();
+			if (relationName == null) relationName = "Relation";
+			this.relationName = relationName;
+			if (parentColumns == null) throw new ArgumentNullException ();
+			this.parentColumns = parentColumns;
+			if (childColumns == null) throw new ArgumentNullException ();
+			this.childColumns = childColumns;
+			this.createConstraints = createConstraints;
+			if (parentColumns.Length != childColumns.Length)
+				throw new InvalidConstraintException ();
+			DataTable parentTable = parentColumns[0].Table;
+			DataTable childTable = childColumns[0].Table;
+			if (parentTable.DataSet != childTable.DataSet)
+				throw new InvalidConstraintException ();
+			foreach (DataColumn column in parentColumns)
+				if (column.Table != parentTable)
+					throw new InvalidConstraintException ();
+			foreach (DataColumn column in childColumns)
+				if (column.Table != childTable)
+					throw new InvalidConstraintException ();
 		}
 
 		[MonoTODO]
@@ -63,32 +85,32 @@
 		[DataCategory ("Data")]
 		[DataSysDescription ("Indicates the child columns of this relation.")]
 		public virtual DataColumn[] ChildColumns {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return childColumns;
 			}
 		}
 
 		public virtual ForeignKeyConstraint ChildKeyConstraint {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return childKeyConstraint;
 			}
 		}
 
+		internal void SetChildKeyConstraint(ForeignKeyConstraint foreignKeyConstraint) {
+			childKeyConstraint = foreignKeyConstraint;
+		}
+
 		public virtual DataTable ChildTable {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return childColumns[0].Table;
 			}
 		}
 
 		[Browsable (false)]
 		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
 		public virtual DataSet DataSet {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return childColumns[0].Table.DataSet;
 			}
 		}
 
@@ -96,7 +118,6 @@
 		[DataCategory ("Data")]
 		[DataSysDescription ("The collection that holds custom user information.")]
 		public PropertyCollection ExtendedProperties {
-			[MonoTODO]
 			get {
 				throw new NotImplementedException ();
 			}
@@ -106,37 +127,36 @@
 		[DataSysDescription ("Indicates whether relations are nested.")]
 		[DefaultValue (false)]
 		public virtual bool Nested {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return nested;
 			} 
 			
-			[MonoTODO]
 			set {
-				throw new NotImplementedException ();
+				nested = value;
 			}
 		}
 
 		[DataCategory ("Data")]
 		[DataSysDescription ("Indicates the parent columns of this relation.")]
 		public virtual DataColumn[] ParentColumns {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return parentColumns;
 			}
 		}
 
 		public virtual UniqueConstraint ParentKeyConstraint {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return parentKeyConstraint;
 			}
 		}
 
+		internal void SetParentKeyConstraint(UniqueConstraint uniqueConstraint) {
+			parentKeyConstraint = uniqueConstraint;
+		}
+
 		public virtual DataTable ParentTable {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return parentColumns[0].Table;
 			}
 		}
 
@@ -144,14 +164,12 @@
 		[DataSysDescription ("The name used to look up this relation in the Relations collection of a DataSet.")]
 		[DefaultValue ("")]
 		public virtual string RelationName {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return relationName;
 			}
 			
-			[MonoTODO]
 			set {
-				throw new NotImplementedException ();
+				relationName = value;
 			}
 		}
 
@@ -159,12 +177,21 @@
 
 		#region Methods
 
-		[MonoTODO]
 		protected void CheckStateForProperty () 
 		{
-			throw new NotImplementedException ();
+			DataTable parentTable = parentColumns[0].Table;
+			DataTable childTable = parentColumns[0].Table;
+			if (parentTable.DataSet != childTable.DataSet)
+			throw new DataException ();
+			bool allColumnsEqual = false;
+			for (int colCnt = 0; colCnt < parentColumns.Length; ++colCnt) {
+				if (!parentColumns [colCnt].DataType.Equals (childColumns [colCnt].DataType))
+					throw new DataException ();
+				if (parentColumns [colCnt] != childColumns [colCnt]) allColumnsEqual = false;
+			}
+			if (allColumnsEqual) throw new DataException ();
 		}
-	
+
 		[MonoTODO]
 		protected internal void OnPropertyChanging (PropertyChangedEventArgs pcevent)
 		{
@@ -177,10 +204,9 @@
 			throw new NotImplementedException ();
 		}
 
-		[MonoTODO]
 		public override string ToString () 
 		{
-			throw new NotImplementedException ();
+			return relationName;
 		}
 
 		#endregion // Methods
Index: System.Data/DataRelationCollection.cs
===================================================================
RCS file: /mono/mcs/class/System.Data/System.Data/DataRelationCollection.cs,v
retrieving revision 1.4
diff -u -r1.4 DataRelationCollection.cs
--- System.Data/DataRelationCollection.cs	12 Nov 2002 01:41:04 -0000	1.4
+++ System.Data/DataRelationCollection.cs	17 Feb 2003 17:07:30 -0000
@@ -5,6 +5,7 @@
 //   Christopher Podurgiel (cpodurgiel@msn.com)
 //   Daniel Morgan <danmorg@sc.rr.com>
 //   Tim Coleman (tim@timcoleman.com)
+//   Alan Tam Siu Lung <Tam@SiuLung.com>
 //
 // (C) Chris Podurgiel
 // (C) 2002 Daniel Morgan
@@ -23,6 +24,135 @@
 	[Serializable]
 	public abstract class DataRelationCollection : InternalDataCollectionBase
 	{
+		/// <summary>
+		/// Summary description for DataTableRelationCollection.
+		/// </summary>
+		internal class DataSetRelationCollection : DataRelationCollection
+		{
+			private DataSet dataSet;
+			
+			/// <summary>
+			/// Initializes a new instance of the DataSetRelationCollection class.
+			/// </summary>
+			internal DataSetRelationCollection (DataSet dataSet)
+			{
+				this.dataSet = dataSet;
+			}
+
+			/// <summary>
+			/// Gets the DataRelation object specified by name.
+			/// </summary>
+			public override DataRelation this [string name]
+			{
+				get {
+					foreach (DataRelation dataRelation in List)
+						if (dataRelation.RelationName == name) return dataRelation;
+					return null;
+				}
+			}
+
+			/// <summary>
+			/// Gets the DataRelation object at the specified index.
+			/// </summary>
+			[MonoTODO]
+			public override DataRelation this [int index]
+			{
+				get {
+					return List [index] as DataRelation;
+				}
+			}
+
+			protected override DataSet GetDataSet()
+			{
+				return dataSet;
+			}
+
+			/// <summary>
+			/// Performs verification on the table.
+			/// </summary>
+			/// <param name="relation">The relation to check.</param>
+			[MonoTODO]
+			protected override void AddCore (DataRelation relation)
+			{
+				base.AddCore (relation);
+				if (relation.ChildTable.DataSet != this.dataSet || relation.ParentTable.DataSet != this.dataSet)
+					throw new DataException ();
+				List.Add (relation);
+				relation.ParentTable.ChildRelations.Add (relation);
+				relation.ChildTable.ParentRelations.Add (relation);
+				ForeignKeyConstraint foreignKeyConstraint = null;
+				if (relation.createConstraints) {
+					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;
+									break;
+								}
+							}
+							if (allColumnsEqual) {
+								uniqueConstraint = uc;
+								break;
+							}
+						}
+					}
+				}
+				relation.SetParentKeyConstraint (uniqueConstraint);
+				relation.SetChildKeyConstraint (foreignKeyConstraint);
+			}
+		}
+
+		/// <summary>
+		/// Summary description for DataTableRelationCollection.
+		/// </summary>
+		internal class DataTableRelationCollection : DataRelationCollection
+		{
+			private DataTable dataTable;
+			
+			/// <summary>
+			/// Initializes a new instance of the DataTableRelationCollection class.
+			/// </summary>
+			internal DataTableRelationCollection (DataTable dataTable)
+			{
+				this.dataTable = dataTable;
+			}
+
+			/// <summary>
+			/// Gets the DataRelation object specified by name.
+			/// </summary>
+			public override DataRelation this [string name]
+			{
+				get {
+					foreach (DataRelation dataRelation in List)
+						if (dataRelation.RelationName == name) return dataRelation;
+					return null;
+				}
+			}
+
+			/// <summary>
+			/// Gets the DataRelation object at the specified index.
+			/// </summary>
+			[MonoTODO]
+			public override DataRelation this [int index]
+			{
+				get {
+					return List [index] as DataRelation;
+				}
+			}
+
+			protected override DataSet GetDataSet()
+			{
+				return dataTable.DataSet;
+			}
+		}
+
 		private int defaultNameIndex;
 		private bool inTransition;
 		
@@ -55,6 +185,7 @@
 		[MonoTODO]
 		public void Add(DataRelation relation)
 		{
+			this.AddCore (relation);
 			if(List != null)
 			{
 				//CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
@@ -76,7 +207,6 @@
 		[MonoTODO]
 		public virtual DataRelation Add(DataColumn parentColumn, DataColumn childColumn)
 		{	
-			
 			if(parentColumn == null)
 			{
 				throw new ArgumentNullException("parentColumn");
@@ -95,6 +225,7 @@
 			*/
 			
 			DataRelation dataRelation = new DataRelation("Relation" + defaultNameIndex.ToString(), parentColumn, childColumn);
+			this.AddCore (dataRelation);
 			//CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
 			List.Add(dataRelation);
 			//OnCollectionChanged(e);
@@ -115,6 +246,7 @@
 		public virtual DataRelation Add(DataColumn[] parentColumns, DataColumn[] childColumns)
 		{
 			DataRelation dataRelation = new DataRelation("Relation" + defaultNameIndex.ToString(), parentColumns, childColumns);
+			this.AddCore (dataRelation);
 			List.Add(dataRelation);
 			defaultNameIndex++;
 			return dataRelation;
@@ -142,6 +274,7 @@
 			}
 
 			DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn);
+			this.AddCore (dataRelation);
 			List.Add(dataRelation);
 			return dataRelation;
 		}
@@ -164,6 +297,7 @@
 			}
 
 			DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns);
+			this.AddCore (dataRelation);
 			List.Add(dataRelation);
 			return dataRelation;
 		}
@@ -191,6 +325,7 @@
 			}
 
 			DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn, createConstraints);
+			this.AddCore (dataRelation);
 			List.Add(dataRelation);
 			return dataRelation;
 		}
@@ -215,7 +350,7 @@
 			}
 
 			DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns, createConstraints);
-			AddCore(dataRelation);
+			AddCore (dataRelation);
 			List.Add(dataRelation);
 			return dataRelation;
 		}
@@ -316,7 +451,7 @@
 
 		public void Remove (DataRelation relation)
 		{
-			RemoveCore (relation);
+			// TODO: RemoveCore (relation);
 			List.Remove (relation);
 			OnCollectionChanged (CreateCollectionChangeEvent (CollectionChangeAction.Remove));
 		}
Index: System.Data/DataRow.cs
===================================================================
RCS file: /mono/mcs/class/System.Data/System.Data/DataRow.cs,v
retrieving revision 1.30
diff -u -r1.30 DataRow.cs
--- System.Data/DataRow.cs	26 Jan 2003 13:38:41 -0000	1.30
+++ System.Data/DataRow.cs	17 Feb 2003 17:07:31 -0000
@@ -555,20 +555,18 @@
 		/// <summary>
 		/// Gets the child rows of this DataRow using the specified DataRelation.
 		/// </summary>
-		[MonoTODO]
 		public DataRow[] GetChildRows (DataRelation relation) 
 		{
-			throw new NotImplementedException ();
+			return GetChildRows (relation, DataRowVersion.Current);
 		}
 
 		/// <summary>
 		/// Gets the child rows of a DataRow using the specified RelationName of a
 		/// DataRelation.
 		/// </summary>
-		[MonoTODO]
 		public DataRow[] GetChildRows (string relationName) 
 		{
-			throw new NotImplementedException ();
+			return GetChildRows (Table.DataSet.Relations[relationName]);
 		}
 
 		/// <summary>
@@ -578,17 +576,32 @@
 		[MonoTODO]
 		public DataRow[] GetChildRows (DataRelation relation, DataRowVersion version) 
 		{
-			throw new NotImplementedException ();
+			// TODO: Caching for better preformance
+			ArrayList rows = new ArrayList();
+			DataColumn[] parentColumns = relation.ParentColumns;
+			DataColumn[] childColumns = relation.ChildColumns;
+			int numColumn = parentColumns.Length;
+			foreach (DataRow row in relation.ChildTable.Rows) {
+				bool allColumnsMatch = true;
+				for (int columnCnt = 0; columnCnt < numColumn; ++columnCnt) {
+					if (!this [parentColumns[columnCnt], version].Equals(
+					    row[childColumns[columnCnt], version])) {
+						allColumnsMatch = false;
+						break;
+					}
+				}
+				if (allColumnsMatch) rows.Add(row);
+			}
+			return rows.ToArray(typeof(DataRow)) as DataRow[];
 		}
 
 		/// <summary>
 		/// Gets the child rows of a DataRow using the specified RelationName of a
 		/// DataRelation, and DataRowVersion.
 		/// </summary>
-		[MonoTODO]
 		public DataRow[] GetChildRows (string relationName, DataRowVersion version) 
 		{
-			throw new NotImplementedException ();
+			return GetChildRows (Table.DataSet.Relations[relationName], version);
 		}
 
 		/// <summary>
Index: System.Data/DataSet.cs
===================================================================
RCS file: /mono/mcs/class/System.Data/System.Data/DataSet.cs,v
retrieving revision 1.33
diff -u -r1.33 DataSet.cs
--- System.Data/DataSet.cs	5 Feb 2003 15:48:57 -0000	1.33
+++ System.Data/DataSet.cs	17 Feb 2003 17:07:33 -0000
@@ -37,7 +37,7 @@
 		private bool caseSensitive;
 		private bool enforceConstraints = true;
 		private DataTableCollection tableCollection;
-		// private DataTableRelationCollection relationCollection;
+		private DataRelationCollection relationCollection;
 		private PropertyCollection properties;
 		private DataViewManager defaultView;
 		private CultureInfo locale;
@@ -52,7 +52,7 @@
 		public DataSet(string name) {
 			dataSetName = name;
 			tableCollection = new DataTableCollection (this);
-			//relationCollection = new DataTableRelationCollection ();
+			relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
 		}
 
 		[MonoTODO]
@@ -201,10 +201,8 @@
 		[DataSysDescription ("The collection that holds the relations for this DatSet.")]
 		[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
 		public DataRelationCollection Relations {
-			[MonoTODO]
-			get{
-				//return relationCollection;		
-				throw new NotImplementedException ();		
+			get {
+				return relationCollection;		
 			}
 		}
 
@@ -389,10 +387,8 @@
 			//Write out each table in order, providing it is not
 			//part of another table structure via a nested parent relationship
 			foreach( DataTable table in Tables )
-			{		
+			{
 				bool isTopLevel = true;
-				//FIXME: Uncomment this when Parentrelations is implemented
-				/*
 				foreach( DataRelation rel in table.ParentRelations )
 				{
 					if( rel.Nested )
@@ -401,7 +397,6 @@
 						break;
 					}
 				}
-				*/
 				
 				if( isTopLevel )
 				{
@@ -599,7 +594,7 @@
 		#endregion
 		
 		#region Protected Methods
-		protected virtual void GetSerializationData(SerializationInfo info, StreamingContext context)
+		protected void GetSerializationData(SerializationInfo info, StreamingContext context)
 		{
 			string s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
 			if (s != null) ReadXmlSerializable (new XmlTextReader(new StringReader(s)));
@@ -630,15 +625,24 @@
 	
 		private void WriteTable( XmlWriter writer, DataTable table, XmlWriteMode mode )
 		{
+			DataRow[] rows = new DataRow [table.Rows.Count];
+			table.Rows.CopyTo (rows, 0);
+			WriteTable (writer, rows, mode);
+		}
+
+		private void WriteTable( XmlWriter writer, DataRow[] rows, XmlWriteMode mode )
+		{
 			//The columns can be attributes, hidden, elements, or simple content
 			//There can be 0-1 simple content cols or 0-* elements
 			System.Collections.ArrayList atts;
 			System.Collections.ArrayList elements;
 			DataColumn simple = null;
 
+			if (rows.Length == 0) return;
+			DataTable table = rows[0].Table;
 			SplitColumns( table, out atts, out elements, out simple );
 
-			foreach( DataRow row in table.Rows )
+			foreach( DataRow row in rows )
 			{
 				//sort out the namespacing
 				string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
@@ -692,7 +696,11 @@
 					}
 				}
 				
-				//TODO write out the nested child relations
+				foreach (DataRelation relation in table.ChildRelations) {
+					if (relation.Nested) {
+						WriteTable (writer, row.GetChildRows(relation), mode);
+					}
+				}
 				
 				writer.WriteEndElement();
 			}
@@ -788,12 +796,9 @@
 			
 			//Write out schema for each table in order, providing it is not
 			//part of another table structure via a nested parent relationship
-			//TODO - is this correct? should I be using nested objects?
 			foreach( DataTable table in Tables )
 			{		
 				bool isTopLevel = true;
-				//FIXME: Uncomment this when ParentRelations class is implemented
-				/*
 				foreach( DataRelation rel in table.ParentRelations )
 				{
 					if( rel.Nested )
@@ -802,7 +807,6 @@
 						break;
 					}
 				}
-				*/
 				
 				if( isTopLevel )
 				{
Index: System.Data/DataTable.cs
===================================================================
RCS file: /mono/mcs/class/System.Data/System.Data/DataTable.cs,v
retrieving revision 1.28
diff -u -r1.28 DataTable.cs
--- System.Data/DataTable.cs	5 Feb 2003 15:48:57 -0000	1.28
+++ System.Data/DataTable.cs	17 Feb 2003 17:07:35 -0000
@@ -40,9 +40,8 @@
 		private CultureInfo _locale;
 		private int _minimumCapacity;
 		private string _nameSpace;
-		// FIXME: temporarily commented
-		// private DataTableRelationCollection _childRelations; 
-		// private DataTableRelationCollection _parentRelations;
+		private DataRelationCollection _childRelations; 
+		private DataRelationCollection _parentRelations;
 		private string _prefix;
 		private DataColumn[] _primaryKey;
 		private DataRowCollection _rows;
@@ -73,9 +72,8 @@
 			//LAMESPEC: spec says 25 impl does 50
 			_minimumCapacity = 50;
 			
-			// FIXME: temporaily commented DataTableRelationCollection
-			// _childRelations = new DataTableRelationCollection();
-			// _parentRelations = new DataTableRelationCollection();
+			_childRelations = new DataRelationCollection.DataTableRelationCollection (this);
+			_parentRelations = new DataRelationCollection.DataTableRelationCollection (this);
 
 		
 			_defaultView = new DataView(this);
@@ -146,13 +144,7 @@
 		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
 		public DataRelationCollection ChildRelations {
 			get {
-				// FIXME: temporarily commented to compile
-				// return (DataRelationCollection)_childRelations;
-				
-				//We are going to have to Inherit a class from 
-				//DataRelationCollection because DRC is abstract
-				
-				throw new NotImplementedException ();
+				return _childRelations;
 			}
 		}
 
@@ -275,9 +267,7 @@
 		[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
 		public DataRelationCollection ParentRelations {
 			get {	
-				// FIXME: temporarily commented to compile
-				// return _parentRelations;
-				throw new NotImplementedException ();
+				return _parentRelations;
 			}
 		}

