C#•Determine the Update Order of DataTables at Run Time

Listing 3. You can always find at least one correct sequence for performing a two-sweeps update procedure as long as the DataTables relationships form an acyclic graph—one with no closed-circuit paths. This is the C# implementation of such an algorithm. Note how the code takes advantage of DataSet's ExtendedProperties to mark a relationship as visited.

ArrayList ar = new ArrayList ();
DataSet ds = new DataSet ();
//set up a Dataset with tables and relationships
ds.ReadXmlSchema (@"dataset1.xsd");
Hashtable ht = new Hashtable ();

//make root table list (no incoming FK constraints)
foreach (DataTable dt in ds.Tables )
	ht.Add (dt.TableName, dt);
foreach(DataRelation dr in ds.Relations)
	if (ht.ContainsKey 
		(dr.ChildTable.TableName))
		ht.Remove (dr.ChildTable.TableName);

//set up DataTable update order. 
//Store it in ar ArrayList variable
foreach(DictionaryEntry de in ht) {
	DataTable dt = (DataTable)de.Value;
	//processTable contains core of algorithm
	processTable (dt,ar);
}

//First sweep: insert-update
foreach (DataTable l_tbl in ar) {
	//suppose the persistInsertAndUpdate method 
	//can find appropriate datadapter for 
	//the provided DataTable
	commitInsertAndUpdate(l_tbl);	 
}
//second sweep: delete
ar.Reverse();
foreach (DataTable l_tbl in ar) 
	//suppose the commitDeletes method 
	//can find the appropriate datadapter for 
	//the provided DataTable
	commitDeletes(l_tbl);	 
}

//the core routine
void processTable(DataTable p_dt, ArrayList p_ar) {
	p_ar.Add (p_dt);
	foreach(DataRelation l_childrel in 
		p_dt.ChildRelations) {
		bool l_ready=true;
		l_childrel.ExtendedProperties.Add 
			("visited",true);
		DataTable l_dtc = 
			l_childrel.ChildTable;
		//Check if there are other incoming 
		//relations not visited yet. If not, 
		//the table is ready to be saved.
		foreach(DataRelation l_parentdatarel 
			in l_dtc.ParentRelations)
			if(l_parentdatarel.
				ExtendedProperties.
				ContainsKey("visited") == false) {
				l_ready=false;
				break ;
			}
			if(l_ready==true) 
				processTable(l_dtc,p_ar);
	}
}