// only used with ADO writers // TODO this method can be greatly simplified protected internal DataSet CreateDataSetFromCursorColumns() { DataSet retval = null; List <TableDef> tables = GetTableInfoFromCursorColumns(); // we have now collected all table info, // we can create a dataset DataTable dt = null; DataTable primaryTable = null; //hack for (int i = 0; i < tables.Count; i++) { if (retval == null) { retval = new DataSet(this._dataSourceName); } TableDef td = tables[i]; try { dt = retval.Tables.Add(td.Name); } catch (DuplicateNameException) { // TODO deal with this // It is a rare exception, but possible. Commence connection names are case-sensitive. // In that case this exception is not thrown, but data can still end up in the wrong datatable (or more likely fail). // we should probably include some pre-check and throw something more meaningful throw; // for now just rethrow to be safe } // define columns DataColumn dc = null; // we need to set some general fields if (td.Primary) // primary table columns { dc = dt.Columns.Add("id", typeof(Int32)); // not auto-incremented! dc.AllowDBNull = false; // hack for setting relations later on. primaryTable = dt; // capture that this is our primary table so we can set relationships later on dt.ExtendedProperties.Add("IsPrimaryTable", true); } else // related table columns { // create a primary key that autoincrements dc = dt.Columns.Add("id", typeof(Int32)); dc.AllowDBNull = false; dc.AutoIncrement = true; // create a foreign key field to reference the connected item dc = dt.Columns.Add("fkid", typeof(Int32)); dc.AllowDBNull = false; // cannot be null } // now process Commence fields // rest of related columns for (int j = 0; j < td.ColumnDefinitions.Count; j++) { try { dc = dt.Columns.Add(td.ColumnDefinitions[j].FieldName); } catch (DuplicateNameException) { // appending some number would decouple the fieldname in the dataset // from the fieldname in the Commence columnset. // for now just rethrow throw; } // set column properties dc.DataType = td.ColumnDefinitions[j].CommenceFieldDefinition.Type.GetTypeForCommenceField(); dc.AllowDBNull = true; // this is default, but setting it explicitly makes it more clear. } } // we would like to set relationships as well. // as it is, we don't know what our 'primary' table is at this point in the code // all we know it is the only table without a fkid field, but that's a little awkward to check. // we hack that by having a 'mock' primary table variable. List <DataRelation> relations = new List <DataRelation>(); foreach (DataTable d in retval.Tables) { if (!d.Equals(primaryTable)) { DataRelation r = new DataRelation("rel_" + d.TableName, primaryTable.TableName, d.TableName, new string[] { "id" }, new string[] { "fkid" }, true); // setting nested to true allows for nested XML exports relations.Add(r); } } // add the relations to the dataset // tricky snag found on https://msdn.microsoft.com/en-us/library/2z22c2sz.aspx // "Any DataRelation object created by using this constructor must be added to the collection // with the AddRange method inside of a BeginInit and EndInit block. if (relations.Any()) { retval.BeginInit(); retval.Relations.AddRange(relations.ToArray()); retval.EndInit(); } return(retval); }