Форум: "Прочее";
Текущий архив: 2010.01.24;
Скачать: [xml.tar.bz2];
ВнизВ порядке обсуждения TDBTreeView. Найти похожие ветки
← →
Jeer © (2009-11-19 18:15) [0]Только ленивый не прикручивал к стандартному TTreeView отображение данных из БД и я не исключение.
Собственно говоря, такой компонент был написан давным-давно и почти все устраивало.
Однако свалилась на голову беда:
- справочники из многих тысяч иерархических записей;
- произвольная СУБД ( да хоть файл-серверная ), но по стд. SQL-92,
никаких тебе серверных процедур и языков в помощь;
- интенсивная работа пользователя со справочниками ( выбор чекбоксами необходимых ветвей на всю их страшную глубину ),
а значит требование высокой скорости отображения и никаких вариантов на постепенное подсос-открытие ветвей.
В общем, практически тупик.
Одна радость - справочники чрезвычайно консервативны и обновление их возможно не в период работы пользователей.
Поскольку ничего путного из опубликованного в Сети не извлек, пришлось идти собственным путем и, вполне возможно, "велосипедным".
В общем, идея свелась к спец.подготовке справочников к линейной схеме их заполнения.
Таблица имеет вид:
ID ( уник. первичный ключ)
PARENT (ссылка на ID для child )
LEVEL ( уровень иерархии текущей записи )
IDX ( индекс записи в treeview ( аналог node.AbsoluteIndex)
NAME ( всякая текстовуха, как обычно )
Поскольку значения в LEVEL, IDX не могут быть совсем уж монстроидальными, то тип полей может быть
и поменьше, чем integer или longint. По ситуации.
Может показаться, что ID и IDX дублируют др.друга, однако это не так.
ID всегда уникален, а IDX может меняться в зависимости от изменения положения записи в дереве.
Итак, что делаем ? Вначале готовим таблицу.
Открываем датасет, тот же TQuery, например путем select * без order или даже с ним.
Считываем стандартно и "медленно", путем сканирования и построения иерархии по Locate ( ID и PARENT )
Получаем в TreeView отображение иерархии, модифицируем ( переставляем, добавляем ) нужные записи, а по окончании
нажимаем волшебную кнопочку "Записать все" и во все записи проставляются абсолютный индекс IDX узла.
Время по вышеуказанной причине не лимитирует.
Итак, таблица готова к ускоренному отображению, но как ?
Переоткрываем датасет с order by IDX - все записи окажутся в линейном порядке по требуемому индексу TreeView (это будет всегда для пользовательских запросов + всякие условия, если надо).
Пропуски значений в IDX при наложении доп.условий не мешают - важен порядок, а он будет сохранен.
Далее, чтобы не напороться на всякие стандартные node := Items[i], поскольку это приведет к замаскированному поиску по TV и лучше от этого не станет,делаем следующий код:
var
pnd,nd: TTreeNode;
pidx,lvl, old_lvl, d, p: integer;
txt: string;
arP: array of pointer;
***
SetLength(arP, quY.RecordCount); // с большим запасом, т.к. указатель p будет периодически прыгать к началу для истинного дерева
p:=0; // указатель позиции в стеке
old_lvl := 0;
pnd := nil;
quTV.First;
dbTV.Items.BeginUpdate;
while not quTV.Eof do begin
// чтение уровня записи
lvl := quTV.FieldByName(fFieldLevelId).AsInteger;
// текстовуха или что надо
txt := quTV.FieldByName(fFieldText).AsString;
d := lvl - old_lvl;
// если ныряем в глубину
if d > 0 then begin
pnd := nd;
Inc(p);
arP[p] := Pointer(pnd);
end;
// если поднимаемся вверх
if d < 0 then begin
p := p + d;
pnd := arP[p];
end;
// по ситуации добавляем паханов или детей
if (lvl=0) then
nd := dbTV.Items.Add(nil, txt)
else
nd := dbTV.Items.AddChild(pnd, txt);
old_lvl := lvl;
quTV.Next;
end; // while
dbTV.Items.EndUpdate;
SetLenght(arP,0);
**************
В итоге такой мазохистский подход дает повышение производительности на два порядка, не меньше.
К примеру из реального - было 800 сек на загрузку, стало 8 сек, что вполне удовлетворительно.
P.S.
Не удивлюсь, что переоткрыл велосипед, ну да я велосипедист :)
← →
oldman © (2009-11-19 18:19) [1]
> Только ленивый не прикручивал к стандартному TTreeView отображение
> данных из БД
Значит, я ленивый.
← →
Германн © (2009-11-19 18:25) [2]Я не ленивый, но более нескольких десятков записей и трех уровней иерархии у меня не было никогда :)
← →
И. Павел © (2009-11-19 18:31) [3]Как вариант работы с иерархией:
incl |name
. |начальник
.abc. |заместитель начальника 1
.def. |заместитель начальника 2
.def.qwe. |заместитель второго заместителя
Такая база занимает побольше места но ее проще обрабатывать, чем базу со ссылкой на родительский элемент.
← →
Омлет © (2009-11-19 18:36) [4]> [0] Jeer © (19.11.09 18:15)
> требование высокой скорости отображения
Лучше бы взять VTV:
http://www.soft-gems.net/index.php?option=com_content&task=view&id=12&Itemid=33
← →
Jeer © (2009-11-20 09:16) [5]
> Германн © (19.11.09 18:25) [2]
>
> Я не ленивый, но более нескольких десятков записей и трех
> уровней иерархии у меня не было никогда :)
>
Значит не всех кошек встречал и не всех умеешь готовить :)
В системах OLAP-класса много чудного встречается, приходится выкручиваться.
> Такая база занимает побольше места но ее проще обрабатывать,
> чем базу со ссылкой на родительский элемент.
Это аналог введения поля LEVEL, причем худший.
> Лучше бы взять VTV:
С творчеством Лишке я знаком, но VTV не DBAware-компонент, а значит проблема отображения реляции на дерево остается.
← →
jack128_ (2009-11-20 13:59) [6]а зачем загружать все элементы дерева сразу?? почему бы просто не грузить только текущий уровень иерархии??
← →
4el0vek (2009-11-20 14:08) [7]
> Омлет © (19.11.09 18:36) [4]
вот кстати да. вполне себе хороший компонент. и быстрый, и весьма гибкий. я вот с ним сейчас активно работаю - удобная вещь. что хорошо - логика работы с данными абстрагирована от отображения данных.
← →
Jeer © (2009-11-20 14:55) [8]
> jack128_ (20.11.09 13:59) [6]
>
> а зачем загружать все элементы дерева сразу?? почему бы
> просто не грузить только текущий уровень иерархии??
Это все понятно и в подобающих случаях это используется, но дело в том в этой задаче, пользователь может чекнуть какую-либо ветку целиком, ее не раскрывая, а это потребует прохода ее вниз, чтобы получить id для формирования запроса вида where F in ( x, y, x,...)
Причем он может это делать многократно, гуляя по разным веткам и даже переоткрывая справочник (не рубить же ему голову за это) и это приведет к значительной задержке в его операциях.
Это вообще особенность OLAP-систем - пользователь занят активным изучением данных.
Диапазон используемых СУБД ( одновременно из одного приложения ) весьма широк, также как и диапазон аппаратных платформ.
Есть даже вариант на CD-ROM ( приложение и временной слепок базы ).
Естественно требуется минимальная вариация в производительности выборок.
Список показателей монстроидален в превосходной степени, но такова задачка :)
http://i026.radikal.ru/0911/ec/ee9b991bdcc9.jpg
http://s39.radikal.ru/i083/0911/c3/988164ef79f4.jpg
← →
Polevi © (2009-11-20 15:10) [9]>Jeer © (20.11.09 14:55) [8]
>ее не раскрывая, а это потребует прохода ее вниз, чтобы получить id для >формирования запроса вида where F in ( x, y, x,...)
зная id узла вовсе не обязательно раскрывать его на клиенте чтобы получить список всех детей
← →
Polevi © (2009-11-20 15:15) [10]к тому же where in (1,2,3,..) рано или поздно натолкнется на ограничение максимальной длины sql запроса для используемой СУБД
← →
Jeer © (2009-11-20 15:20) [11]
> зная id узла вовсе не обязательно раскрывать его на клиенте
> чтобы получить список всех детей
Таково ограничение - бизнес процессы только на клиенте. Серваки отдыхают от процедур. :)
>натолкнется на ограничение максимальной длины
Ну не надо понимать все буквально - есть еще всякие маленькие хитрости, снижающие такие риски.
Схема БД - это "снежинка", а не "звезда".
← →
ANB (2009-11-20 15:48) [12]
> Jeer © (20.11.09 15:20) [11]
Сколько извращений - аж жуть. :)
Отображение дерева руками писал еще на клиппере.
Всего элементов было мало -несколько тысяч (классификатор товаров небольшого магазина).
Тормозов не было.
В оракле спасает connect by, результат легко отображается в дерево.
Вышепрочитанное еще раз убеждает меня, что лучше оракла СУБД нету :)
← →
Jeer © (2009-11-20 15:54) [13]
> ANB (20.11.09 15:48) [12]
К сожалению потребовалась "некоторая" универсальность, за которую приходится платить извращениями, увы. Но работает :)
Серваки ( ORACLE, MS SQL, Firebird, Linter,...) стоят чистые и свободные от шаловливых ручек sql-дизайнеров :)
Кушают исключительно SQL-92, такая вот демократия.
← →
ANB (2009-11-20 17:01) [14]
> Кушают исключительно SQL-92
Вот это - полный изврат. Зачем ставить оракл, если им нельзя пользоваться ?
← →
jack128_ (2009-11-20 17:08) [15]
> Вот это - полный изврат. Зачем ставить оракл, если им нельзя
> пользоваться ?
угу, я кста тоже не понимаю. в конце концов кроссБДейзность всегда можно на хранимками скрыть.
← →
Jeer © (2009-11-23 09:33) [16]
> ANB (20.11.09 17:01) [14]
>
>
> > Кушают исключительно SQL-92
>
> Вот это - полный изврат. Зачем ставить оракл, если им нельзя
> пользоваться ?
Т.е. без хранимок и триггеров и прочей исключительной для конкретного сервака лабуды это уже и не SQL-сервак ?
Хэх.. Вам бы 64к полной памяти и 8-разрядный процессор и DBase II.
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2010.01.24;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.007 c