3

DataTable「ツリーデータ構造」を保持するオブジェクトがあります。データはどのデータベースにも保存されません。DataTable を使用して、SQL サーバーなしでデータを操作します。

私のデータは次のようになります (インデントはここで読みやすくするためだけです):

DataTable dtCategories = GetCategoriesAsDataTable();

id    name    parentId
int   string  int
----------------------
 1    One         0
 2      OneA      1
 3      OneB      1
 4    Two         0
 5      TwoA      4
 6      TwoB      4
 7        TwoAA   5
 8        TwoAB   5

これまでのところ、「where parentId = 0」で最初のレベルを選択し、これを別の DataTable に配置することを考えていました。

DataTable dtFirstLevel = dtCategories.Select("[parentId] = 0");

// and after this - create DataTable for second level
// but I don't know how can I use "IN" clause here
DataTable dtSecondLevel = dtCategories.Select(?????????);
  1. ツリーの最初の 2 レベルのみを選択するにはどうすればよいですか?
  2. これを SQL サーバーなしで (データ オブジェクトのみを使用して) 選択するにはどうすればよいですか?
4

5 に答える 5

2

この関数は、各エントリのツリーのレベルを把握して、選択に使用できるようにするのに役立つと思います。

    public int level(DataTable dt, DataRow row)
    {
        int parentid = int.Parse(row[2].ToString());
        if (parentid == 0)
            return 1;
        else
            return 1 + level(dt, GetDataRow(dt,parentid ));
    }

    public DataRow GetDataRow(DataTable dt, int id)
    {
        foreach (DataRow r in dt.Rows)
        {
            if (int.Parse(r[0].ToString()) == id) return r;
        }
        return null;
    }
于 2013-09-25T14:33:08.037 に答える
1
DataTable level1 = (from t in dtCategories.AsEnumerable()
                    where t.Field<int>("parentId") == 0
                    select t).CopyToDataTable();

DataTable level2 =(from t1 in dtCategories.AsEnumerable()
                        join t2 in dtCategories.AsEnumerable() 
                           on t1.Field<int>("id") equals t2.Field<int>("parentId")
                   where t1.Field<int>("parentId") == 0
                   select t2).CopyToDataTable();
于 2013-09-25T14:48:27.700 に答える
1

問題にはいくつかのオプションがあります。@Ali が提案したように、次のような再帰を使用できます。

public int level(DataTable dt, DataRow row)
{
    int parentid = int.Parse(row[2].ToString());
    if (parentid == 0)
        return 1;
    else
        return 1 + level(dt, GetDataRow(dt,parentid ));
}

public DataRow GetDataRow(DataTable dt, int id)
{
    foreach (DataRow r in dt.Rows)
    {
        if (int.Parse(r[0].ToString()) == id) return r;
    }
    return null;
}

しかし、問題は、すべての要素を繰り返し処理し、すべての繰り返しで再帰を使用することになります。親 ID 以外に、列とツリー内のレベルとの間にデータ関係がまったくない場合は、これが唯一の解決策です。

一方、名前 [A] がツリー レベル 1 で、名前 [AB] がツリー レベル 2 のような関係がある場合は、次のように各ノードを繰り返します。

    foreach (DataRow r in dt.Rows)
    {
        //Pull out the element
        //Check the element's level
       //Add it to the result set if level <= 2
    }

個人的には、実際にツリー構造を構築するか、SQL WHERE 句を使用して問題を解決したいと考えていますが、その時間を正当化するのは困難です。このデータをどこから取得するかによっては、挿入された場所に応じてノードがどのレベルにあるかを示す追加の列を追加することもできます。祖父母 (つまり、2 つの親ノード) がある場合は、結果セットに含めません。

于 2013-09-25T14:45:54.487 に答える