Nachdem ich viele Tage daran gearbeitet habe, habe ich es geschafft, dieses Problem selbst zu lösen. Was ich getan habe, war Folgendes;
In meiner ursprünglichen untergeordneten Klasse erstellen der MemberCode und der ElementCode dann einen eindeutigen Schlüssel, der im Wesentlichen den Spaltennamen angibt. Also ging ich noch einen Schritt weiter und fügte einen "Column_Name" hinzu, sodass ich
hattepublic class Child
{
public int MemberCode { get; set; } //Composite key
public int ElementCode { get; set; } //Composite key
public string Column_Name { get; set; } //Unique. Alternative Key
public Object Data { get; set; }
}
Dies spiegelte sich offensichtlich auch in meiner Datenbanktabelle wider.
Mein SQL zum Extrahieren der Daten sah dann so aus;
select p.UniqueID, p.LoadTime, p.reference, c.MemberCode, c.ElementCode , c.column_name, c.Data
from parent as p, child as c
where p.UniqueID = c.UniqueID
//aditional filter criteria
ORDER BY p.UniqueID, MemberCode, ElementCode
Die erste Sortierung nach der UniqueID ist entscheidend, um sicherzustellen, dass die Datensätze für die spätere Verarbeitung in der richtigen Reihenfolge sind.
Ich würde einen dynamic
verwenden und ein ExpandoObject()
um die Daten zu speichern.
Also iteriere ich über das Ergebnis, um das SQL-Ergebnis wie folgt in diese Struktur umzuwandeln:
List<dynamic> allRecords = new List<dynamic>(); //A list of all my records
List<dynamic> singleRecord = null; //A list representing just a single record
bool first = true; //Needed for execution of the first iteration only
int lastId = 0; //id of the last unique record
foreach (DataRow row in args.GetDataSet.Tables[0].Rows)
{
int newID = Convert.ToInt32(row["UniqueID"]); //get the current record unique id
if (newID != lastId) //If new record then get header/parent information
{
if (!first)
allRecords.Add(singleRecord); //store the last record
else
first = false;
//new object
singleRecord = new List<dynamic>();
//get parent information and store it
dynamic head = new ExpandoObject();
head.Column_name = "UniqueID";
head.UDS_Data = row["UniqueID"].ToString();
singleRecord.Add(head);
head = new ExpandoObject();
head.Column_name = "LoadTime";
head.UDS_Data = row["LoadTime"].ToString();
singleRecord.Add(head);
head = new ExpandoObject();
head.Column_name = "reference";
head.UDS_Data = row["reference"].ToString();
singleRecord.Add(head);
}
//get child information and store it. One row at a time
dynamic record = new ExpandoObject();
record.Column_name = row["column_name"].ToString();
record.UDS_Data = row["data"].ToString();
singleRecord.Add(record);
lastId = newID; //store the last id
}
allRecords.Add(singleRecord); //stores the last complete record
Dann habe ich meine Informationen dynamisch in der von mir gewünschten flachen Weise gespeichert.
Das nächste Problem war nun die ObjectListView, die ich verwenden wollte. Dies konnte solche dynamischen Typen nicht akzeptieren.
Ich hatte also die Informationen wie gewünscht in meinem Code gespeichert, konnte sie aber immer noch nicht wie erforderlich anzeigen.
Die Lösung bestand darin, eine Variante des ObjectListView
zu verwenden bekannt als DataListView
. Dies ist praktisch das gleiche Steuerelement, kann aber datengebunden sein. Eine andere Alternative wäre auch die Verwendung einer DatagridView, aber ich wollte aus anderen Gründen bei der ObjectListView bleiben.
Also musste ich jetzt meine dynamischen Daten in eine Datenquelle konvertieren. Dies habe ich wie folgt gemacht;
DataTable dt = new DataTable();
foreach (dynamic record in allRecords)
{
DataRow dr = dt.NewRow();
foreach (dynamic item in record)
{
var prop = (IDictionary<String, Object>)item;
if (!dt.Columns.Contains(prop["Column_name"].ToString()))
{
dt.Columns.Add(new DataColumn(prop["Column_name"].ToString()));
}
dr[prop["Column_name"].ToString()] = prop["UDS_Data"];
}
dt.Rows.Add(dr);
}
Dann weise ich einfach meine Datenquelle der DataListView zu, generiere die Spalten, und schwupps habe ich jetzt meine dynamischen Daten extrahiert, reduziert und wie gewünscht angezeigt.