2012-04-24 5 views
0

ОК, я использую Embarcadero Delphi 2010. В настоящее время я использую файл базы данных Access с именем flib.mdb в этом файле, я создаю таблицу с именем MCategory, которая имеет 4 (четыре) столбца с именем: codecategory в виде текстового и первичного ключей, parentcategory как Текст, category как текст, notes как текст.Как показать родительскую категорию в delphi 2010?

Для подключения к базе данных я использую ADOConnection. Для запроса я использую ADOQuery. Для таблицы я использую ADOTable.

Код для авторождения с префиксом, но для примера я использую регулярное число как строку.

Существует только один корень: codecategory="0" // parentcategory="" // category="ROOT" не имеет права другой ROOT (один с пустым parentcategory)

Мой вопрос заключается в том, как remasking все parentcategory, как на картинке ниже? А как посмотреть его на DBGrid?

parent category masking

Должен ли я использовать рекурсивный? Есть ли простой способ сделать это?

А также исходный код на Delphi 2010, пожалуйста .... ^^

+0

использовать значение NULL в качестве ROOT для ForeignKey использованием. – MajidTaheri

+0

Я бы предпочел сделать это задание на стороне сервера, а не выбирать все категории, а затем рекурсивно перебирать их для создания пути. Попытайтесь прочитать ['this article'] (http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/). Это для MySQL, но есть полезная информация о том, как создать иерархическую структуру базы данных, в том числе, как получить желаемый путь к дереву. Гораздо быстрее будет также использовать codecategory и parentcategory как NUMBER, а не TEXT. – TLama

+0

ну, к сожалению, нет необходимости в клиент-сервере на этом, и он должен использовать Access/mdb –

ответ

0

Вы можете преобразовать все записи набора данных TStringList и сортировки его.

в интерфейсе секции объявить следующим образом:

TForm1=class(...) 
    RecordList:TStringList; 
    constructor Create(AOwner:TComponent);override; 
destructor Destroy;override; 

end; 
TCategoryItem=class 
public: 
    CategoryTitle:string; 
    Id,ParentId:Variant; 
end; 

в секции реализации:

constructor TForm1.Create(AOwner: TComponent); 
begin 
    inherited ; 
    RecordList:=TstringList.create(true); // use this code in FormCreate also 


end; 
destructor TForm1.Destroy; 
    begin 
     ... 
    RecordList.Free;// use this code in FormDestory also 

    end; 

procedure TForm1.AdoQuery1AfterOpen(DataSet:TDataSet); 
var 
    Item,RootItem:TCategoryItem; 
begin 
    DataSet.First; 
    DataSet.DisableControls; 

    try 
    (*add abstract root item to RecordList if needed 
    RootItem:=TCategoryItem.Create; 
    RootItem.CategoryTitle:='ROOT'; 
    RecordList.AddObject('',RootItem);*) 
    while not DataSet.Eof do 
    begin 
     Item:=TCategoryItem.Create; 
     Item.CategoryTitle:=DataSet['Cateogory']; 
     Item.Id:=DataSet['CodeCategory']; 
     Item.ParentId:=DataSet['ParentCategory']; 
     RecordList.AddObject(VarToStr(Item.Id),Item); 
     DataSet.Next; 
    end; 
    finally 
    RecordList.Sort; // for use find(binary search) 
    DataSet.EnableControls; 
    DataSet.First; 
    end; 
end; 
procedure TForm1.OnGetFieldText(Sender: TField; var Text: string; 
    DisplayText: Boolean); 
var 
    Idx:Integer; 
    ParentValue:Variant; 
    Item:TCategoryItem; 
    Texts:TStringList; 
begin 
    ParentValue:=Sender.Value; 
    Texts:=TStringList.create; 
    try 
    while RecordList.Find(varToStr(ParentValue),Idx) do 
    begin 
     Item:=RecordList.Objects[Idx] as TCategoryItem; 
     Texts.Insert(0,Item.CategoryTitle); 
     ParentValue:=Item.ParentId; 
    end; 
    Texts.Delimiter:='>'; 
    Text:=Texts.DelimitedText; 
    finally 
    Texts.Free; 
    end; 


end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    ADOQuery1.FieldByName('parentcategory').OnGetText := OnGetFieldText; 
    ADOQuery1.Refresh; 
end; 
+1

Вы можете использовать события OnCreate и OnDestroy, а не переопределять конструктор и деструктор формы. Также 'TField.OnGetText' используется, когда вы хотите изменить текст, который будет отображаться для одного поля, а не для вычислений набора данных; это будет задачей для «TDataset.OnCalcFields», но все же я бы предпочел сделать это на стороне БД, а не выбирать все категории и рекурсивно перебирать для каждого поля (это может быть очень неэффективно, если вы считаете огромное количество данные). – TLama

+0

И забыл упомянуть, OP использует Delphi 2010, поэтому почему бы не использовать, например. 'TDictionary' вместо' TStringList'. – TLama

+0

Позвольте мне попробовать это первое ^^ –