prapti.n3 Ответов: 4

Преобразование datatable во вложенный список <>


У меня есть таблица данных следующим образом

ID    Name   ParentID
1      A       0
2      B       1
3      C       1
4      D       2
5      E       3
6      F       4


Я хочу этого как ... List<chart>

//Chart.cs
 public int ID { get; set; }
 public string Name { get; set; }
 public string ParentID{ get; set; }
 public List<chart> lstChild{ get; set; }


Что я уже пробовал:

Я уже пробовал эту функцию:

public static void MakeTree(DataTable dt, clsChart parent)
        {
            foreach (DataRow row in dt.AsEnumerable().Where(x => x.Field<int>("ParentID") == parent.ID))
            {
                if (parent.lstChildren == null)
                {
                    parent.lstChildren = new List<clschart>();
                }
                clsChart newNode = new clsChart();
                newNode.Name = row.Field<string>("Name");
                newNode.ID = row.Field<int>("EntryID");
                parent.lstChildren.Add(newNode);
                MakeTree(dt, newNode);
            }
        }


Но он не возвращается List<>, он возвращает класс

4 Ответов

Рейтинг:
2

Maciej Los

Что касается меня, то ваш datatable разработан должным образом для иерархическая модель данных[^]. Вот почему а chart модель должна отражать в модели datatable.

public class chart
{
	public int ID { get; set; }
 	public string Name { get; set; }
	public int ParentID{ get; set; }
}


Это очень легко создать List<chart> из объекта DataTable:
List<chart> charts = dt.AsEnumerable()
    .Select(dr=> new chart()
        {
            ID=dr.Field<int>("ID"),
            Name=dr.Field<string>("Name"),
            ParentID=dr.Field<int>("ParentID")
        })
    .ToList();


Приведенная выше модель представляет собой "плоскую" версию иерархических данных. Если вы хотите создать более продвинутую иерархическую структуру, пожалуйста, прочтите это: Рекурсивные иерархические объединения в C# и LINQ - Bitlush[^]


Рейтинг:
2

OriginalGriff

Во-первых, ParentID должен быть int не string

Во-вторых, вам вообще не нужна рекурсия, и при условии, что ваши родительские узлы всегда определяются до их дочерних узлов, вы можете использовать один цикл. (Если это случайный порядок, то сначала создайте коллекцию узлов, а затем выполните цикл через нее:

class Chart
    {
    private static Dictionary<int, Chart> all = new Dictionary<int, Chart>();
    public int ID { get; set; }
    public string Name { get; set; }
    public int ParentID { get; set; }
    public List<Chart> Children { get; set; } = new List<Chart>();
    private Chart(DataRow row)
        {
        ID = (int)row["ID"];
        Name = (string)row["Name"];
        ParentID = (int)row["ParentID"];
        all[ID] = this;
        }
    public static Chart MakeTree(DataTable dt)
        {
        List<Chart> nodes = new List<Chart>();
        Chart root = null;
        foreach (DataRow row in dt.AsEnumerable())
            {
            Chart node = new Chart(row);
            if (node.ParentID == 0)
                {
                if (root != null) throw new ArgumentException("Too many ROOT nodes: only one was expected.");
                root = node;
                }
            else
                {
                if (root == null) throw new ArgumentException("ROOT node has not been defined: one is required.");
                Chart parent = all[node.ParentID];
                parent.Children.Add(node);
                }
            }
        return root;
        }
    }

DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("ParentID", typeof(int));
dt.Rows.Add(1, "A", 0);
dt.Rows.Add(2, "B", 1);
dt.Rows.Add(3, "C", 1);
dt.Rows.Add(4, "D", 2);
dt.Rows.Add(5, "E", 3);
dt.Rows.Add(6, "F", 4);
Chart root = Chart.MakeTree(dt);


prapti.n3

Но я хочу, чтобы он был в списке<chart> типа не как объект диаграммы

OriginalGriff

У вас есть один корневой узел: он содержит список всех дочерних элементов диаграммы. Единственный список всех элементов, который вы можете создать, будет содержать один элемент: корневой узел. Все остальные являются дочерними узлами этого корня.

Так зачем тебе это вообще нужно?

prapti.n3

Потому что это только пример. Данные, над которыми я работаю, имеют 3-4 корня с родительским идентификатором 0.

OriginalGriff

Поэтому создайте "фиктивный узел" с идентификатором 0, а затем верните дочерний список из него!

Или добавьте коллекцию узлов для возврата и добавьте к ней все узлы с родителем 0 вместо того, чтобы ограничивать ее одним корнем.

Рейтинг:
1

Gerry Schmitz

Вы можете рекурсивно создавать (и связывать) свои узлы, но вам также нужен "главный список", который вы добавляете при создании каждого узла.

"Главный список" представляет собой полностью развернутое дерево; узел может быть расширен / свернут, если у него есть дочерние элементы.

"Консервированные" древовидные представления поддерживают внутренний "список древовидных представлений" (то же самое).

"Уровень" каждого элемента определяет отступ.

Добавление "номера уровня" полезно при создании дерева. С помощью номера уровня вы также можете определить родителя, если таковой имеется, при использовании составных ключей.


Рейтинг:
1

prapti.n3

List<clschart> lstChart = новый список<clschart>();
строка JSONresult;

//var roots = dt.Методом asenumerable().Список();
lstChart = clsDataTables.ConvertDataTable<clschart>(dt);
ВАР корней = lstChart.Где(f => f.ParentID == 0).Список();
//(из n в dt.Методом asenumerable (), где N.Поле И Л;int> У("атрибутом parentId") == 0 группы N на N.Поле И Л;int> У("атрибутом parentId")).Список();
по каждому элементу (корень ВАР в корнях)
клшарт.BuildTree(root, lstChart);

JSONresult = JsonConvert.SerializeObject(корни, форматирование.Изрезанный);