Mewakili struktur pohon dari db

Saya telah membaca tentang berbagai cara untuk merepresentasikan struktur hierarki dalam database relasional seperti Adjacency List.

Saya telah memutuskan untuk mencoba cara langsung seperti tabel (yang terlalu disederhanakan) yang dilakukan seperti ini: id | name | parent di mana induk adalah referensi dalam ke id.

Ini seharusnya cukup untuk mewakili pohon sederhana dengan kedalaman yang tidak ditentukan.

Sekarang, bagaimana cara membuat pohon untuk mewakili struktur data semacam ini? Misalnya, jika saya ingin membuat XML atau rangkaian <ul><li> bersarang untuk mencetaknya dalam format HTML, cara apa yang paling efisien untuk mengulang node? Saya ingin tahu apakah Linq dapat membantu, tetapi saya juga tertarik pada jawaban yang lebih umum (tidak terikat .NET) dan teoretis.

Terima kasih sebelumnya.


person pistacchio    schedule 24.06.2009    source sumber
comment
Beberapa jawaban bagus ada di sini: stackoverflow.com/questions/192220/   -  person Tomalak    schedule 25.06.2009


Jawaban (1)


Ironisnya, bagian tersulit dari masalah ini adalah mendapatkan sekumpulan catatan terbatas dari database yang memenuhi predikat jalur tertentu. Kecuali Anda menggunakan database yang menyediakan dukungan kueri hierarki (seperti CONNECT BY Oracle), ini bisa menjadi sangat rumit. Lihat pertanyaan SO ini untuk beberapa pendekatan pada bagian itu.

Namun, anggaplah Anda telah berhasil memuat data Anda ... Anda dapat melakukannya ke dalam kumpulan objek khusus, atau ke dalam Kumpulan Data, atau ke dalam struktur XML (jika Anda tidak peduli memanipulasi data selain sebagai string). Jika Anda memiliki objek khusus, Anda bisa menambahkan properti yang mengekspos koleksi anak dengan menanyakan seluruh kumpulan data untuk catatan yang cocok dengan kunci induk (lihat contoh di bawah). Jika jumlah rekamannya banyak, hal ini mulai menjadi non-performa karena biaya pencarian koleksi. Di sinilah solusi DataSet bersinar - karena Anda dapat menambahkan indeks khusus pada kolom ParentID yang akan meningkatkan kinerja pencarian. Anda dapat membaca tentang Kumpulan Data yang Diketik di sini untuk mempelajari lebih lanjut tentang cara memperluas contoh di bawah ini ke arah itu.

Berikut ini contoh objek khusus dengan dukungan navigasi pohon. Saya menggunakan struktur direktori (folder) karena merupakan contoh alami dari data hierarki. Sekali lagi, berhati-hatilah dalam menggunakan kode ini tanpa struktur yang diindeks karena traversal anak penuh akan menjadi O(n2).

class Folder  // could be converted to a DataRow-derivative
{
    public int Id          { get; set; }
    public string Name     { get; set; }
    public int? ParentId   { get; set; }

    public IEnumerable<Folder> GetChildren( IEnumerable<Folder> allFolders )
    {
        // NOTE: becomes expensive on large hierarchies on unindexed data
        //   a slightly better version, could replace IEnumerable<Folder>
        //   with IOrderedEnumerable<Folder> which would allow the use of
        //   a binary search algorithm for finding children (assuming it's
        //   ordered on the ParentId property).
        return AllFolders.Where( x => x.ParentId.HasValue && 
                                      x.ParentId.Value = this.Id );
    }
}

// elsewhere in your code...

void LoadAndPrintFolders()
{
   // load the folder data... from database, or wherever
   IEnumerable<Folder> allFolders = LoadFolders();

   // find all root folders (let's say, those that have a null ParentId
   IEnumerable<Folder> rootFolders = 
          allFolders.Where( x => !x.ParentId.HasValue );

   // iterate over all of the data as a tree structure...
   foreach( var folder in rootFolders )
   {
       PrintFolder( allFolders, folder, 0 );
   }

}

// recursive function to print all folders...
void PrintFolder( IEnumerable<Folder> allFolders, Folder f, int level )
{
    Console.WriteLine( "{0}{1}", new string('\t',level), f.Name );
    foreach( var folder in f.GetChildren( allFolders )
    {
        PrintFolder( allFolders, folder, level + 1 );
    }
}
person LBushkin    schedule 25.06.2009