首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

動態樹形結構管理:資料庫驅動的節點增刪改與層級編碼解析

     編輯:Delphi

設計目標

支援龐大樹狀資料 (如圖書分類、組織架構) 的動態載入、新增、修改、刪除,且不將整棵樹序列化儲存,而是將結構分散在資料庫每筆記錄的編碼欄位中,實現「按需載入、效能優異」。

核心資料結構:層級編碼 (LongID)

每筆記錄擁有固定長度編碼 LongID (範例 6 碼),格式定義:CTreeCodeFormat = '122222' 表示:

  • 第 1 層:1 碼
  • 第 2-6 層:各 2 碼
  • 最大 6 層 (cTreeMaxLevel = 6)

範例:

節點LongID層級父節點 LongID 前綴
根節點0000000-
文學1000001000000 (取前 1 碼)
小說1010002100000 (取前 3 碼)
武俠1010103101000 (取前 5 碼)

關鍵函數實作

1. 解析編碼層級 GetNodeLevel

function GetNodeLevel(const Format, Code: string): Integer;
var I, AccLen: Integer;
begin
  Result := -1;
  AccLen := 0;
  for I := 1 to Length(Format) do begin
    AccLen := AccLen + StrToInt(Format[I]);
    if Length(Code) = AccLen then begin
      Result := I;
      Break;
    end;
  end;
end;

2. 依編碼查找 TreeView 節點索引 GetNodeItem

function GetNodeItem(const Code: string): Integer;
var I: Integer; Tmp: string;
begin
  Result := 0;
  for I := 0 to Tree.Items.Count - 1 do begin
    Tmp := Copy(Tree.Items[I].Text, 1, Pos('-', Tree.Items[I].Text) - 1);
    if Tmp = Code then begin Result := I; Break; end;
  end;
end;

樹狀載入主流程 LoadTree

procedure LoadTree(TreeDB: TDataSet);
var CurID, NodeTxt: string; Level: Integer;
    NodeArray: array[0..6] of TTreeNode;  // 索引=層級,值=該層最新節點
begin
  Screen.Cursor := crHourGlass;
  Tree.Items.Clear;
  Tree.Enabled := True;
  
  // 根節點
  NodeArray[1] := Tree.Items.Add(nil, CTreeRootTxt);  // '所有圖書'
  NodeArray[1].ImageIndex := 0; NodeArray[1].SelectedIndex := 1;
  
  TreeDB.Open;
  TreeDB.First;
  while not TreeDB.Eof do begin
    CurID := Trim(TreeDB.FieldByName('tsglb').AsString);  // 編碼
    NodeTxt := CurID + '-' + Trim(TreeDB.FieldByName('tsglbn').AsString); // 顯示文字
    Level := GetNodeLevel(CTreeCodeFormat, CurID);
    
    if Level > 0 then begin
      // 父節點 = 上一層最新節點
      NodeArray[Level] := Tree.Items.AddChild(NodeArray[Level-1], NodeTxt);
      NodeArray[Level].ImageIndex := 2;
      NodeArray[Level].SelectedIndex := 3;
    end;
    TreeDB.Next;
  end;
  
  NodeArray[1].Expand(False);  // 展開根節點
  TreeDB.Close;
  Screen.Cursor := crDefault;
end;

動態更新操作 UpdateTree

procedure UpdateTree(var CurNode: TTreeNode; const NodeTxt, State: string);
begin
  if State = 'add' then begin
    CurNode := Tree.Items.AddChild(CurNode, NodeTxt);
    CurNode.ImageIndex := 2; CurNode.SelectedIndex := 3;
  end
  else if State = 'del' then
    CurNode.Delete
  else if State = 'edi' then
    CurNode.Text := NodeTxt;
end;

資料庫同步策略

操作TreeView 動作資料庫 SQL
新增AddChildINSERT INTO TreeTable (LongID, Name) VALUES (:NewCode, :Name)
修改Node.Text := NewNameUPDATE TreeTable SET Name = :Name WHERE LongID = :Code
刪除Node.Delete (含所有子孫)DELETE FROM TreeTable WHERE LongID LIKE :Code + '%'

虛擬模式優化:按需載入子節點

大量資料時,OnExpanding 事件動態查詢資料庫:

procedure TForm1.TreeView1Expanding(Sender: TObject; Node: TTreeNode; var AllowExpansion: Boolean);
var Qry: TQuery; Child: TTreeNode; ParentCode: string;
begin
  Child := Node.GetFirstChild;
  // 檢查佔位節點 (Text 為空、Data=nil)
  if (Child <> nil) and (Child.Text = '') and (Child.Data = nil) then begin
    Child.Delete;
    ParentCode := GetNodeCode(Node);  // 從 Node.Data 或 Text 解析
    Qry.SQL.Text := 'SELECT LongID, Name FROM TreeTable WHERE LongID LIKE :Prefix AND Level = :Lvl';
    Qry.ParamByName('Prefix').AsString := ParentCode + '%';
    Qry.ParamByName('Lvl').AsInteger := Node.Level + 1;
    Qry.Open;
    while not Qry.Eof do begin
      NewNode := Tree.Items.AddChildObject(Node, Qry.FieldByName('Name').AsString, 
                                           TObject(Qry.FieldByName('LongID').AsString));
      // 若有子節點,加入佔位節點
      if HasChildren(Qry.FieldByName('LongID').AsString) then
        Tree.Items.AddChildObject(NewNode, '', nil);
      Qry.Next;
    end;
  end;
end;

ID 生成策略 (關鍵難點)

  • 序號遞增:同層級最大值 +1,不足位數左補 0
  • 間隔預留:每次遞增 10 或 100,留空間供插入排序
  • GUID 映射:資料庫用 GUID 主鍵,TreeView 顯示用映射後的短編碼
  • 重編碼:定期離線重編整棵樹 (維護窗口執行)

總結

以固定長度層級編碼 (LongID) 為核心,結合 NodeArray[Level] 追蹤各層最新節點,可高效載入龐大樹狀結構。動態操作同步更新資料庫與 TreeView,虛擬模式進一步支援百萬級節點。關鍵在編碼規則設計與 ID 生成策略,需依業務增長模式權衡簡單性與擴展性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved