Mysql
 sql >> Database >  >> RDS >> Mysql

Dati figlio/genitore appiattiti con numero sconosciuto di colonne

Dopo molti giorni di lavoro su questo, sono riuscito a risolvere questo problema da solo. Quello che ho fatto è stato il seguente;

Nella mia classe figlia originale, il MemberCode e l'ElementCode creano una chiave univoca che in pratica affermava quale fosse il nome della colonna. Quindi ho fatto un ulteriore passo avanti e ho aggiunto un "Column_Name" in modo da avere

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; }
}

Ciò si rifletteva ovviamente anche nella tabella del mio database.

Il mio SQL per estrarre i dati era quindi simile a questo;

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

l'ordine in base all'ID unico è fondamentale per garantire che i record siano nell'ordine corretto per l'elaborazione successiva.

Userei un dynamic e un ExpandoObject() per memorizzare i dati.

Quindi ripeto il risultato per convertire il risultato sql in questa struttura come segue;

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

Quindi ho le mie informazioni archiviate dinamicamente nel modo piatto che avevo richiesto.

Ora il problema successivo era ObjectListView che volevo usare. Questo non può accettare tali tipi dinamici.

Quindi avevo le informazioni memorizzate nel mio codice come volevo, ma non potevo ancora visualizzarle come richiesto.

La soluzione era utilizzare una variante di ObjectListView noto come DataListView . Questo è effettivamente lo stesso controllo ma può essere associato ai dati. Un'altra alternativa sarebbe anche usare un DatagridView, ma volevo attenermi a ObjectListView per altri motivi.

Quindi ora dovevo convertire i miei dati dinamici in un'origine dati. L'ho fatto come segue;

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);
}

Quindi assegno semplicemente la mia origine dati a DataListView, genero le colonne e, presto, ora ho i miei dati dinamici estratti, appiattiti e visualizzati come richiesto.