c# - 展平具有未知列数的子/父数据

标签 c# mysql sql

我正在努力寻找存储和表示 SQL (MySQL DB) 和 C# Windows 表单中的数据的最佳方法。

我的数据映射到如下所示的类;

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

我的数据非常动态。因此父记录可以有任意数量的子记录。

在子记录中,MemberCode 和 ElementCode 实际上是其他表/类的外键,当执行查找时,它们会提供有关数据实际内容的详细信息。例如

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

它们有效地组合起来指示列名是什么,并且它们始终相同(因此 MemberCode = 1 & ElementCode = 1 将始终是 Date,无论它与哪个子对象关联)。 目前这些是引用/查找,但我也可以将数据放入类中的变量中,因为这可能会更容易。那么它就更像是一个键值对。

目前在我的数据库中,我将它们存储为两个表,子记录还包含来自父记录的 UniqueID。但我不确定这是否是最好的方法,正如我将解释的那样。

我的表是这样创建的

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`)
)

现在我想要做的是展平这些数据,以便我可以将单个父记录与所有子记录显示为一行。理想情况下,我希望将其显示在 ObjectListView ( http://objectlistview.sourceforge.net/cs/index.html ) 中,但如果它能让生活更轻松,可以考虑使用数据网格。

因为我的数据是动态的,所以我很难将其展平,如果我选择 10 个父记录,那么每个父记录可以有不同数量的子元素,并且每个可以有不同的 MemberCodes 和 ElementCode,这意味着它们实际上是不同的列。

所以我的数据可能如下所示(但规模更大);

My Data

但是由于数据的动态特性,我很难做到这一点。在我的代码中的 SQL 或对象中。也许还有另一种更适合它的方式来存储我的数据。

最佳答案

经过很多天的努力,我自己成功解决了这个问题。我所做的如下;

在我原来的子类中,MemberCode 和 ElementCode 生成一个唯一的键,基本上说明了列名是什么。所以我更进一步,添加了一个“Column_Name”,这样我就有了

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

这显然也反射(reflect)在我的数据库表中。

我的 SQL 提取数据看起来像这样;

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

首先按 UniqueID 排序对于确保记录以正确的顺序供以后处理至关重要。

我将使用 dynamicExpandoObject() 来存储数据。

因此,我迭代结果,将 sql 结果转换为此结构,如下所示;

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

然后我以我需要的扁平方式动态存储我的信息。

现在下一个问题是我想使用的 ObjectListView。这无法接受此类动态类型。

因此,我按照需要将信息存储在代码中,但仍然无法按要求显示它。

解决方案是使用 ObjectListView 的变体,称为 DataListView。这实际上是相同的控件,但可以进行数据绑定(bind)。 另一种选择也是使用 DatagridView,但由于其他原因我想坚持使用 ObjectListView。

所以现在我必须将动态数据转换为数据源。我这样做如下;

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

然后,我只需将数据源分配给 DataListView,生成列,嘿,现在我已经提取、展平并显示了我需要的动态数据。

关于c# - 展平具有未知列数的子/父数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36350480/

相关文章:

c# - 为什么我收到 'Invariant unproven' 警告

php - 我可以在 laravel 查询生成器中同时使用 `join` 和 `with` 吗?

java - 使用java执行查询时,返回多行时如何验证结果文本?

mysql - 更新语句给出未知列错误

sql - Xcode iOS 电话目录应用程序。核心数据、sqlite 或

mysql - group_concat() 不根据数据排序

c# - CS0103 : The name 'CType' does not exist in the current context

c# - 动态向我的 View 添加新行

php - 从MySQL获取数据时出现 undefined variable 错误

c# - 将数据从平面数组转换为层次结构