3

C#言語を使用しています。私の問題は、取得した階層的な結果セットをオブジェクトに保存する方法がわからないことです。

ここに私のオブジェクトがあります:

public class CategoryItem
{
    public string Name { get; set; }
    public int CategoryID { get; set; }
    public int ParentID { get; set; }
    public List<CategoryItem> SubCategory = new List<CategoryItem>();
    public List<CategoryItem> GetSubCategory()
    {
        return SubCategory;
    }
    public void AddSubCategory(CategoryItem ci)
    {
        SubCategory.Add(ci);
    }
    public void RemoveSubCategory(CategoryItem ci)
    {
        for (int i = 0; i < SubCategory.Count; i++)
        {
            if (SubCategory.ElementAt(i).CategoryID == ci.CategoryID)
            {
                SubCategory.RemoveAt(i);
                break;
            }
        }
    }
}

これは、MSSQLサーバーからデータセットを取得するサンプルです

ID  PrntID  Title   
_______ _______     
1   0   Node1   
2   1   Node2   
3   1   Node3   
4   2   Node4   
5   2   Node5   
6   2   Node6   
7   3   Node7   
8   4   Node8   
9   4   Node9   
10  9   Node10

簡単に参照できるツリー ビュー

Node 1
-Node 2
--Node 4
---Node 8
---Node 9
----Node 10
--Node 5
--Node 6
-Node 3
--Node 7

私の問題は、この結果を「CategoryItem オブジェクト」に保存する方法です。これに反復を使用する必要があるかどうかはわかりませんか?特に、ノードが 2 レベルの深さの場合。私はそれを次のように保存したい:

List<CategoryItem> items = new List<CategoryItem>();

これにより、「アイテム」オブジェクト内のすべてのオブジェクトを掘り下げることができ、クラスの GetSubCategory() メソッドを使用してそのサブカテゴリ/子/子にアクセスできます。これは可能ですか?

4

3 に答える 3

2

DataSetでノードが親の前に表示されないことがわかっている場合は、このコードを使用できます。ここでは、新しく読み取られたノードの親を探すことができるときに、ディクショナリですでに読み取られたアイテムを追跡します。親が見つかった場合は、その子に新しいアイテムを追加します。それ以外の場合は、第1レベルのノードです。

    public static List<CategoryItem> LoadFromDataSet(DataSet aDS)
    {
        List<CategoryItem> result = new List<CategoryItem>();
        Dictionary<int, CategoryItem> alreadyRead = new Dictionary<int, CategoryItem>();
        foreach (DataRow aRow in aDS.Tables["YourTable"].Rows)
        {
            CategoryItem newItem = new CategoryItem();
            newItem.CategoryID = (int)aRow["ID"];
            newItem.ParentID = (int)aRow["PrntID"];
            newItem.Name = (string)aRow["Title"];
            alreadyRead[newItem.CategoryID] = newItem;
            CategoryItem aParent;
            if (alreadyRead.TryGetValue(newItem.ParentID, out aParent))
                aParent.AddSubCategory(newItem);
            else
                result.Add(newItem);
        }
        return result;
    }

私の仮定が正しくない場合(つまり、ノードがその親の前にDataSetに表示される可能性がある場合)、最初にすべてのノードを読み取り(そしてそれらをディクショナリに配置し)、次に同じディクショナリをループしてビルドする必要があります結果。このようなもの:

    public static List<CategoryItem> LoadFromDataSet(DataSet aDS)
    {
        List<CategoryItem> result = new List<CategoryItem>();
        Dictionary<int, CategoryItem> alreadyRead = new Dictionary<int, CategoryItem>();
        foreach (DataRow aRow in aDS.Tables["YourTable"].Rows)
        {
            CategoryItem newItem = new CategoryItem();
            newItem.CategoryID = (int)aRow["ID"];
            newItem.ParentID = (int)aRow["PrntID"];
            newItem.Name = (string)aRow["Title"];
            alreadyRead[newItem.CategoryID] = newItem;
        }
        foreach (CategoryItem newItem in alreadyRead.Values)
        {
            CategoryItem aParent;
            if (alreadyRead.TryGetValue(newItem.ParentID, out aParent))
                aParent.AddSubCategory(newItem);
            else
                result.Add(newItem);
        }
        return result;
    }
于 2012-05-31T04:55:58.913 に答える
0

これを実現するには、再帰的なコードを書く必要があります。

//First of all, find the root level parent
int  baseParent = "0"; 
// Find the lowest root parent value
 foreach (var selection in collection)
 {
     //assign any random parent id, if not assigned before
      if (string.IsNullOrEmpty(baseParent))
        baseParent = selection["PrntID"];

     //check whether it is the minimum value
     if (Convert.ToInt32(selection["PrntID"]) < Convert.ToInt32(baseParent))
       baseParent = selection["PrntID"];
 }
//If you are sure that your parent root level node would always be zero, then you could   //probably skip the above part.
//Now start building your hierarchy
foreach (var selection in collection)
{
  CategoryItem item = new CategoryItem();
  //start from root
  if(selection["Id"] == baseParentId)
  {
    //add item property
    item.Id = selection["id];
    //go recursive to bring all children
    //get all children
    GetAllChildren(item , collection);
  }
}


private void GetAllChildren(CategoryItem parent, List<Rows> Collection)
{
  foreach(var selection in Collection)
  {
     //find all children of that parent
     if(selection["PrntID"] = parent.Id)
     {
       CategoryItem child = new CategoryItem ();
       //set properties
       child.Id = selection["Id"];
       //add the child to the parent
       parent.AddSubCategory(child);
       //go recursive and find all child for this node now
       GetAllChildren(child, Collection);
     }
   }
}

注: これは正確に機能するコードではありません。しかし、これにより、オブジェクトとして表現する必要がある階層データ構造を構築する方法についての洞察が得られます。

于 2012-05-31T05:03:55.047 に答える
0

テーブルをデータテーブルにロードし、最初にルートノードを見つけてルートオブジェクトを作成します

DataRow[] rootRow = table.Select("PrntID = 0");
CategoryItem root = new CategoryItem() { CategoryID = (int)rootRow[0]["ID"].ToString(), Name = rootRow[0]["Title"].ToString(), ParentID = (int)rootRow[0]["PrntID"].ToString() };

次に、再帰メソッドを呼び出してサブカテゴリを追加する必要があります。

GetCategoryItem((int)rootRow[0]["ID"].ToString(), root);

必要に応じて以下の方法を変更してください。

public void GetCategoryItem(CategoryItem parant)
{
    DataRow[] rootRow = table.Select("PrntID =" + parant.CategoryID);
    for (int i = 0; i < rootRow.Length; i++)
    {
        CategoryItem child = new CategoryItem() { CategoryID = (int)rootRow[i]["ID"].ToString(), Name = rootRow[i]["Title"].ToString(), ParentID = (int)rootRow[i]["PrntID"].ToString() };
        GetCategoryItem(child);
        parant.SubCategory.Add(child);
    }
}
于 2012-05-31T05:04:42.893 に答える