Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Dados filho/pai achatados com número desconhecido de colunas


Depois de muitos dias trabalhando nisso, consegui resolver esse problema sozinho. O que eu fiz foi o seguinte;

Na minha classe filha original, o MemberCode e o ElementCode criam uma chave exclusiva que basicamente declara qual era o nome da coluna. Então dei um passo adiante e adicionei um "Column_Name" para que eu tivesse
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; }
}

Obviamente, isso também se refletiu na minha tabela de banco de dados.

Meu SQL para extrair os dados ficou assim;
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

ordenar primeiro pelo UniqueID é fundamental para garantir que os registros estejam na ordem correta para processamento posterior.

O eu usaria um dynamic e um ExpandoObject() para armazenar os dados.

Então eu itero sobre o resultado para converter o resultado sql nesta estrutura da seguinte forma;
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

Então eu tenho minhas informações armazenadas dinamicamente da maneira simples que eu precisava.

Agora, o próximo problema era o ObjectListView que eu queria usar. Isso não pode aceitar esses tipos dinâmicos.

Então, eu tinha as informações armazenadas no meu código como eu queria, mas ainda não consegui exibi-las como era necessário.

A solução foi usar uma variante do ObjectListView conhecido como DataListView . Este é efetivamente o mesmo controle, mas pode ser vinculado a dados. Outra alternativa também seria usar um DatagridView, mas eu queria manter o ObjectListView por outros motivos.

Então agora eu tive que converter meus dados dinâmicos em uma fonte de dados. Isso eu fiz da seguinte forma;
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);
}

Então eu simplesmente atribuo minha fonte de dados ao DataListView, gero as colunas, e pronto, agora tenho meus dados dinâmicos extraídos, nivelados e exibidos como eu preciso.