2016-04-01 2 views
0

Ich bin schwer zu finden, die beste Möglichkeit zum Speichern und Darstellen der Daten, die ich in SQL (MySQL DB) und C# -Fenster Form haben.Flattern Kind/Eltern Daten mit unbekannter Anzahl von Spalten

Meine Daten bei der Zuordnung zu Klassen, die so aussieht;

public class Parent 
{ 
     public string UniqueID { get; set; } //Key 
     public DateTime LoadTime { get; set; } 
     public string Reference { get; set; } 
     private List<Child> Elements { get; set; } 
} 

public class Child 
{ 
     public int MemberCode { get; set; } //Composite key 
     public int ElementCode { get; set; } //Composite key 
     public Object Data { get; set; } 
} 

Meine Daten sind sehr dynamisch. Ein übergeordneter Datensatz kann also beliebig viele untergeordnete Datensätze enthalten.

In dem Kind-Datensatz sind der MemberCode und der ElementCode tatsächlich Fremdschlüssel zu anderen Tabellen/Klassen, die mir beim Nachschlagen Details darüber geben, was die Daten tatsächlich sind. Zum Beispiel

MemberCode = 1 & ElementCode = 1 means data is a Date 
MemberCode = 1 & ElementCode = 3 means data is a telephone number 
MemberCode = 2 & ElementCode = 11 means data is a Product Code 
MemberCode = 2 & ElementCode = 12 means data is a Service Code 
etc 

Diese kombinieren, um effektiv zu zeigen, was der Spaltenname ist, und diese sind immer die gleichen sind (so MemberCode = 1 & Elemente = 1 wird immer ein Datum sein, egal welches Kind Objekt sie zugeordnet ist) . Im Moment sind dies Referenzen/Nachschlagewerke, aber ich könnte auch die Daten in eine Variable in der Klasse einfügen, da dies die Arbeit erleichtern könnte. Dann wäre es eher wie ein Schlüsselwertpaar.

Im Moment habe ich diese in meiner DB als zwei Tabellen gespeichert, wobei der Kind-Datensatz auch die UniqueID vom Eltern enthält. Aber ich bin mir nicht sicher, ob das der beste Weg ist, wie ich erklären werde.

Meine Tabellen sind als solche

erstellt
CREATE TABLE `PARENT` (
     `ID` INT(11) NOT NULL AUTO_INCREMENT, 
     `LOADTIME` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 
     `REFERENCE` VARCHAR(100) NOT NULL, 
     PRIMARY KEY (`ID`) 
    ) 

CREATE TABLE `CHILD` (
    `ID` INT(11) NOT NULL, 
    `MEMBER_CODE` INT(11) NOT NULL, 
    `ELEMENT_CODE` INT(11) NOT NULL, 
    `DATA` VARCHAR(4000) NULL DEFAULT NULL, 
    PRIMARY KEY (`ID`, `MEMBER_CODE`, `ELEMENT_CODE`), 
    CONSTRAINT `fk_ID` FOREIGN KEY (`ID`) REFERENCES `Parent` (`ID`) 
) 

Nun will ich tun, was ist, diese Daten zu glätten, so dass ich einen einzigen übergeordneten Datensatz mit allen untergeordneten Datensätzen als eine einzelne Zeile angezeigt werden kann. Ich möchte es idealerweise in einer ObjectListView (http://objectlistview.sourceforge.net/cs/index.html) anzeigen, kann aber DataGrid berücksichtigen, wenn es das Leben erleichtert.

Da meine Daten dynamisch sind, habe ich Mühe, dies zu verflachen, und wenn ich 10 übergeordnete Datensätze auswähle, kann jede unterschiedliche Anzahl von untergeordneten Elementen haben, und jedes Element kann verschiedene MemberCodes und ElementCode haben effektiv verschiedene Spalten.

So könnten meine Daten wie folgt aussehen (aber in einem größeren Maßstab);

My Data

Aber wegen der dynamischen Natur der Daten, dann kämpfe ich, dies zu tun. Entweder in SQL oder in Objekten in meinem Code. Vielleicht gibt es sogar noch eine andere Möglichkeit, meine Daten besser zu speichern.

+0

Können Sie bitte Ihre Datenbankobjekte skripten, damit wir sehen können, wie Sie diese Objekte gerade speichern? Kann ein Elternteil mehrere Kinder mit demselben ElementCode haben? Ist die Liste aller ElementCodes auch fest oder dynamisch? – ironstone13

+0

Ich habe die DB create-Skripte für die Tabellen hinzugefügt und den memberCode, elementCode geklärt. Grundsätzlich sind diese immer gleich, über alle untergeordneten Objekte hinweg. –

+0

Bitte geben Sie auch an, ob die Liste der Eigenschaften fest ist - d. H., Sie fügen häufig Paare '{MemberCode; ElementCode}' hinzu - oder sind sie vordefiniert? – ironstone13

Antwort

0

Nachdem ich viele Tage damit gearbeitet habe, habe ich es geschafft, dieses Problem selbst zu lösen. Was ich getan habe, war folgendes;

In meiner ursprünglichen Kindklasse machen der MemberCode und der ElementCode einen eindeutigen Schlüssel, der im Wesentlichen den Spaltennamen angibt. Also nahm ich einen Schritt weiter und fügte ein „Column_Name“, so dass ich

hatte
public 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 ist offensichtlich in meiner Datenbank-Tabelle als auch widerspiegelte.

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 

Reihenfolge zuerst durch die UniqueID ist wichtig, um sicherzustellen, dass die Datensätze in der richtigen Reihenfolge für die spätere Verarbeitung sind.

Ich würde eine dynamic und eine ExpandoObject() verwenden, um die Daten zu speichern.

Also ich über das Ergebnis iterieren, um das SQL-Ergebnis in diese Struktur wie folgt 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 flachen Art gespeichert, die ich benötigte.

Jetzt war das nächste Problem die ObjectListView, die ich verwenden wollte. Dies könnte solche dynamischen Typen nicht akzeptieren.

So hatte ich die Informationen in meinem Code gespeichert, wie ich wollte, aber ich konnte es immer noch nicht anzeigen, wie es erforderlich war.

Die Lösung war, dass eine Variante der ObjectListView als DataListView bekannt zu verwenden war. Dies ist effektiv die gleiche Kontrolle, kann aber datengebunden sein. Eine andere Alternative wäre auch, eine DatagridView zu verwenden, aber ich wollte aus anderen Gründen an der ObjectListView bleiben.

So, jetzt musste ich meine dynamischen Daten in eine Datenquelle konvertieren. Das habe ich folgendermaßen 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 einfach ich meine Datenquelle zum DataListView zuweisen, um die Spalten zu erzeugen, und schwupps Ich habe jetzt meine dynamischen Daten extrahieren, abgeflacht und angezeigt, wie ich brauche.