นำเสนอโครงสร้างต้นไม้จาก db

ฉันได้อ่านเกี่ยวกับวิธีการต่างๆ ในการแสดงโครงสร้างลำดับชั้นภายในฐานข้อมูลเชิงสัมพันธ์ เช่น Adjacency List

ฉันได้ตัดสินใจลองใช้วิธีที่ตรงไปตรงมาเหมือนตาราง (แบบง่ายเกินไป) โดยทำดังนี้: id | name | parent โดยที่ parent เป็นการอ้างอิงภายในถึง id

นี่ควรจะเพียงพอที่จะแสดงถึงต้นไม้ธรรมดาๆ ที่มีความลึกที่ไม่ได้กำหนดไว้

ตอนนี้ ฉันจะสร้างแผนผังเพื่อแสดงโครงสร้างข้อมูลประเภทนี้ได้อย่างไร เช่น ถ้าฉันต้องการสร้าง XML หรือชุดของ <ul><li> ที่ซ้อนกันเพื่อพิมพ์ในรูปแบบ HTML วิธีใดที่มีประสิทธิภาพที่สุดในการวนซ้ำโหนดต่างๆ ฉันสงสัยว่า Linq สามารถช่วยได้หรือไม่ แต่ฉันก็สนใจคำตอบทั่วไป (ไม่ใช่. NET) และคำตอบทางทฤษฎีด้วย

ขอบคุณล่วงหน้า.


person pistacchio    schedule 24.06.2009    source แหล่งที่มา
comment
คำตอบที่ดีบางส่วนอยู่ที่นี่: stackoverflow.com/questions/192220/   -  person Tomalak    schedule 25.06.2009


คำตอบ (1)


น่าแปลกที่ส่วนที่ยากที่สุดของปัญหานี้คือการได้รับชุดระเบียนที่มีข้อจำกัดจากฐานข้อมูลที่เป็นไปตามเพรดิเคตของพาธเฉพาะ เว้นแต่ว่าคุณกำลังใช้ฐานข้อมูลที่ให้การสนับสนุนการสืบค้นแบบลำดับชั้น (เช่น CONNECT BY ของ Oracle) สิ่งนี้อาจมีความซับซ้อนมาก ลองดู คำถาม SO นี้ สำหรับแนวทางบางอย่างในส่วนนั้น

แต่สมมติว่าคุณสามารถโหลดข้อมูลของคุณได้ ... คุณสามารถทำได้ในคอลเลกชันออบเจ็กต์ที่กำหนดเอง หรือชุดข้อมูล หรือในโครงสร้าง XML (หากคุณไม่สนใจเกี่ยวกับการจัดการข้อมูลอื่นนอกเหนือจากนี้ สตริง) หากคุณมีออบเจ็กต์แบบกำหนดเอง คุณสามารถเพิ่มคุณสมบัติที่เปิดเผยคอลเลกชันย่อยได้โดยการสืบค้นชุดข้อมูลทั้งหมดสำหรับบันทึกที่ตรงกับคีย์หลัก (ดูตัวอย่างด้านล่าง) หากจำนวนเรกคอร์ดมีขนาดใหญ่ สิ่งนี้จะเริ่มไม่มีประสิทธิภาพเนื่องจากต้องเสียค่าใช้จ่ายในการค้นหาคอลเลกชัน นี่คือจุดที่โซลูชัน DataSet โดดเด่น เนื่องจากคุณสามารถเพิ่มดัชนีที่กำหนดเองในคอลัมน์ ParentID ที่จะปรับปรุงประสิทธิภาพของการค้นหา คุณสามารถอ่านเกี่ยวกับชุดข้อมูลที่พิมพ์ได้ที่นี่เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับวิธีขยาย ตัวอย่างด้านล่างในทิศทางนั้น

นี่คือตัวอย่างของออบเจ็กต์แบบกำหนดเองที่รองรับการนำทางแบบต้นไม้ ฉันใช้โครงสร้างไดเร็กทอรี (โฟลเดอร์) เนื่องจากเป็นตัวอย่างทั่วไปของข้อมูลแบบลำดับชั้น ขอย้ำอีกครั้ง โปรดระวังการใช้โค้ดนี้โดยไม่มีโครงสร้างที่จัดทำดัชนีไว้ เนื่องจากการแวะผ่านรายการย่อยแบบเต็มจะเป็น 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