简体   繁体   English

创建分层类结构,循环遍历数据表,然后添加父和子以及返回对象

[英]Create hierarchical class structure , loop through data table and then add parent and child and return object

I want to create a class structure that can represent the following heirarchichal structure of objects all of the same type 我想创建一个类结构,它可以表示以下所有相同类型的对象的heirarchichal结构

-Parent1
- - Child1 
- - - ChildA of Child1
- - - ChildB of Child1
- - Child2 
- - - ChildA of Child2
- - - ChildB of Child2
- Parent2

The datatable rows have an ID, ParentID, name and level 数据表行具有ID,ParentID,名称和级别

level is O for Parent, 1 for Child 1 , 2 for ChildA and so on 父级为0,子级为1,ChildA为2,依此类推

I'm able to return the data from the DB to a datatable but am struggling after that any help on creating the class structure and then populating the object would be greatly appreciated 我能够将数据从数据库返回到数据表,但是在创建类结构然后填充对象的任何帮助之后我都会非常感激

Here is an example on how to do that using LINQ. 以下是使用LINQ如何执行此操作的示例。 First a sampe datatable. 首先是一个样本数据表。 I assume that top-level items have a parent ID of 0. 我假设顶级项目的父ID为0。

var dataTable = new DataTable();
dataTable.Columns.Add("Id", typeof(Int32));
dataTable.Columns.Add("ParentId", typeof(Int32));
dataTable.Columns.Add("Name", typeof(String));
dataTable.Rows.Add(new Object[] { 1, 0, "A" });
dataTable.Rows.Add(new Object[] { 2, 1, "B" });
dataTable.Rows.Add(new Object[] { 3, 1, "C" });
dataTable.Rows.Add(new Object[] { 4, 0, "D" });
dataTable.Rows.Add(new Object[] { 5, 4, "E" });

A class to represent each item of data: 表示每个数据项的类:

class Item {

  public Int32 Id { get; set; }

  public String Name { get; set; }

  public IEnumerable<Item> Children { get; set; }

}

A function to get the children of a specific item: 获取特定项目的子项的函数:

IEnumerable<DataRow> GetChildren(DataTable dataTable, Int32 parentId) {
  return dataTable
    .Rows
    .Cast<DataRow>()
    .Where(row => row.Field<Int32>("ParentId") == parentId);
}

A function to create an item including the child collection. 用于创建包括子集合的项的函数。 This function will recurse down the hierarchy: 此函数将递归层次结构:

Item CreateItem(DataTable dataTable, DataRow row) {
  var id = row.Field<Int32>("Id");
  var name = row.Field<String>("Name");
  var children = GetChildren(dataTable, id)
    .Select(r => CreateItem(dataTable, r))
    .ToList();
  return new Item { Id = id, Name = name, Children = children };
}

A function to get rows of the top-level items: 获取顶级项目行的函数:

IEnumerable<DataRow> GetTopLevelRows(DataTable dataTable) {
  return dataTable
    .Rows
    .Cast<DataRow>()
    .Where(row => row.Field<Int32>("ParentId") == 0);
}

Putting it all together: 把它们放在一起:

var items = GetTopLevelRows(dataTable)
  .Select(row => CreateItem(dataTable, row))
  .ToList();

Given the information above you could do this with just one class. 鉴于上述信息,您可以只使用一个类来完成此操作。

public class MyItem
{
  public IList<MyItem> ChildItems{get;set;}
}

Here you've basically got an object that can contain a collection of its own type as children, and thus, those children can contain collections of MyItem too as sub-children. 在这里你基本上得到了一个对象,它可以包含一个自己类型的集合作为子对象,因此,这些子对象也可以包含MyItem的集合作为子子对象。

Consider the following: 考虑以下:

var parentItem = new MyItem()
var childItem = new MyItem();
var childChildItem = new MyItem();

childItem.ChildItems.Add(childChildItem);
parentItem.ChildItems.Add(childItem);

There are nicer ways to code the adding of items but this breaks it down logically enough for the concept to be clear. 有更好的方法可以对项目的添加进行编码,但这样可以在逻辑上将其分解为足以使概念清晰明了。

Here's my approach. 这是我的方法。

Start with the data defined in the question: 从问题中定义的数据开始:

var dataTable = new DataTable();
dataTable.Columns.Add("Id", typeof(int));
dataTable.Columns.Add("ParentId", typeof(int));
dataTable.Columns.Add("Name", typeof(String));
dataTable.Rows.Add(new Object[] { 1, 0, "Parent1" });
dataTable.Rows.Add(new Object[] { 2, 1, "Child1" });
dataTable.Rows.Add(new Object[] { 3, 2, "ChildA of Child1" });
dataTable.Rows.Add(new Object[] { 4, 2, "ChildB of Child1" });
dataTable.Rows.Add(new Object[] { 5, 1, "Child2" });
dataTable.Rows.Add(new Object[] { 6, 5, "ChildA of Child2" });
dataTable.Rows.Add(new Object[] { 7, 5, "ChildB of Child2" });  
dataTable.Rows.Add(new Object[] { 8, 0, "Parent2" });

Then just do this: 然后就这样做:

var lookup = dataTable.Rows.Cast<DataRow>().ToLookup(x => x.Field<int>("ParentId"));

Func<int, Item[]> build = null;
build = n =>
    lookup[n]
        .Select(dr => new Item()
            {
                Id = dr.Field<int>("Id"),
                Name = dr.Field<string>("Name"),
                Children = build(dr.Field<int>("Id")),
            })
            .ToArray();

var items = build(0);

That gives: 这给了:

项目

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM