![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Иерархия объектов в БД
jack128 © (2007-01-15 18:01:00)Есть некая иерархия объектов.
TParent = class
property Prop1;
property Prop2;
property Prop3;
end;
TChild1 = class(TParent)
property C1Prop1;
property C1Prop2;
end;
TChild2 = class(TParent)
property C2Prop1;
property C2Prop2;
end;
Вот всё это дело должно хранится в БД. Как?
A)
в одну таблицу запихнуть все поля в одну таблицу:
Prop1 Prop2 Prop3 C1Prop1 C1Prop2 C2Prop1 C2Prop2
соответственно часть полей будет всегду null'евыми. Неприятно это выглядит. С другой строны - все запросы - просты как валенок.
B)
Все свойства из TParent хранить в одной таблице, а для каждого наследника нарисовать доп. таблицу, в которой хранить специфические свойства + ссылка на базовую таблицу. Получаем тучу left join'ов если нужно получить разом все объекты(а такая необходимость есть) + для усложняется сохранение объектов в БД. Вобщем грустно это..
С)
На каждый Child - класс своя таблица. Типа
Child1Tlb (Prop1, Prop2, Prop3, C1Prop1, C1Prop2)
Child2Tlb (Prop1, Prop2, Prop3, C2Prop1, C2Prop2).
Ну это вообще не вариант - на самом деле, так как нужны FK на TParent.
Собственно как это обычно реализуется?
atruhin (2007-01-15 19:30:00) [21]Нда, до боли похоже, хоть и шли разными путями! :)
Мы в прикладном ПО не использем интерпретаторов, пока нет времени, но есть идеи,
но все равно так как описания классов храняться в БД, иконки класса, форматы ввода полей, ограничения,
рускоязычное название и т.п. Активно используем универсальные редакторы для простых справочников,
универсальный эксплорер БД, он же обеспечиват выбор любых объектов для ссылочных полей,
плюс еще ряд специализированных визуальных и невизуальных компонентов.
В итоге примерно полгода затраченные на доводку структуры БД, написание компонентов и
каркаса программы, окупаются с лихвой.
Ega23 (2007-01-15 19:29:00) [22]
> Именно на триггерах ФК и реализованы!
Здесь другое, здесь за ссылочной целостностью самому придётся следить. Особенно, если в свойствах твоего класса есть ссылка на другой класс. Там если городить FK средствами СУБД - просто умереть можно. Да и расширяемости не получишь простой.
Johnmen (2007-01-15 19:25:00) [23]
> atruhin © (15.01.07 19:14) [12]
> ...тем более, что для IB/FB сделать поддержку FK на
> процедурах/тригерах невозможно (если я чего нового не упустил).
Именно на триггерах ФК и реализованы!
Ega23 (2007-01-15 19:19:00) [24]
> Например: общая для всех объектов таблица связанна 1:1 с
> доп таблицей (таблица полей класса),
> а FK при необходимости создается на эту доп. таблицу.
Так точно. На уровне базового класса есть поле ObjID - суть уникальный идентификатор объекта в рамках всех объектов всех классов. Далее, есть таблица ObjectClasses (ClassID FK на Classes и ObjID)/ Каждая запись в классовой таблице ссылается на ObjectClasses.ObjID.
Т.е. ObjectClasses фактически список всех объектов по всем классам.
Ega23 (2007-01-15 19:16:00) [25]
> Т.е. к каждому классу можно обращаться как к одной обычной
> таблице,
> все остальное на тригерах (права доступа (уровня документа),
> модификация и т.д.).
Совершенно верно. Более того, при таком подходе ещё и as работает.
Т.е. можно получить данные всех объектов-потомков Custom-класса.
Только триггеры мы не используем: во-первых, предполагается, что прямых вставок в таблицы не бывает, всё только через клиентское приложение (а там нормально и хп оборачивается), а во-вторых, у шефа откуда-то предубеждение насчёт триггеров... :о)
atruhin (2007-01-15 19:14:00) [26]> [9] jack128 © (15.01.07 19:04)
> А FK как поддерживаются?
ФК в данной структуре поддерживаются на уровне БД, тем более, что для IB/FB сделать поддержку FK на
процедурах/тригерах невозможно (если я чего нового не упустил).
Например: общая для всех объектов таблица связанна 1:1 с доп таблицей (таблица полей класса),
а FK при необходимости создается на эту доп. таблицу.
atruhin (2007-01-15 19:10:00) [27]> [5] Ega23 © (15.01.07 18:38)
Да, неплохой вариант, у нас БД на том же принципе работает,
только используються не процедуры, а модифицируемые представления.
Т.е. к каждому классу можно обращаться как к одной обычной таблице,
все остальное на тригерах (права доступа (уровня документа), модификация и т.д.).
Ega23 (2007-01-15 19:09:00) [28]
> так я не понял, у вас значения унаследованных свойств в
> этой же таблице хранятся? А FK как поддерживаются? Руками
> через SP? Ну ты же понимаешь, что это совсем грусно. Если
> таки есть таблицы для предков, то фактически B + свои метаданные.
>
Блин... Так долго всё объяснять надо будет...
Я, вполне вероятно, в пятницу в Москве появлюсь, на собеседование поеду... :)
Есть маза вечером пересечься. Заодно все кишки и расскажу... :о)
jack128 (2007-01-15 19:04:00) [29]Johnmen (15.01.07 18:37) [4]
Ну для БД то какая разница, как это называть?
Хм. Можно пример? Что то я вообще не понимаю о чем ты говоришь.
Johnmen (15.01.07 18:37) [4]
Тогда их кол-во = макс. количеству св-в к.-л. класса. Соот-но разрежение минимально...
Хм, ты с вариантом С не спутал? В первом варианте как раз много разреженных данных. В третьем их нет вообще, но это бред. Все FK нужно будет руками поддерживать.
Ega23 © (15.01.07 18:38) [5]
Фактически, каждая запись в таблице реального класса - суть экземпляр объекта, а значения его полей - это его свойства
так я не понял, у вас значения унаследованных свойств в этой же таблице хранятся? А FK как поддерживаются? Руками через SP? Ну ты же понимаешь, что это совсем грусно. Если таки есть таблицы для предков, то фактически B + свои метаданные.
PEAKTOP © (15.01.07 18:49) [6]
Это ты Тенцера почитал?
Спасибо, но я уже переболел этой универсальной структурой БД ;-) Это структура безумно избыточна. Ты хотя бы понятие классов ввёл...
Ega23 (2007-01-15 18:59:00) [30]
> PEAKTOP © (15.01.07 18:49) [6]
Коль по строкам сравниваешь, нехило к Upper всё привести... ИМХО...
PEAKTOP (2007-01-15 18:55:00) [31]Сорри, ошибка вышла. Надо:
CREATE PROCEDUREGET_OBJECT_PROP( -- Получает список свойств по имени объекта по иерархии
Q_OBJECT_ID VARCHAR(50) -- Имя объекта
) RETURNS(
OBJECT_ID VARCHAR(50), -- Объект, от которого унаследовано свойство
ID VARCHAR(50), -- имя свойства
PROP_VALUE VARCHAR(255) -- значение
) AS
BEGIN
OBJECT_ID = :Q_OBJECT_ID;
WHILE(:OBJECT_ID IS NOT NULL) DO
BEGIN
FOR
SELECTP.ID, P.PROP_VALUE
FROM PROPERTIES P
WHERE(P.OBJECT_ID = :OBJECT_ID)
INTO :ID, :PROP_VALUE
DO
SUSPEND;
SELECT FIRST1 O.PARENT_ID FROMOBJECTS O WHERE(O.ID = :OBJECT_ID) INTO:OBJECT_ID;
END
END
PEAKTOP (2007-01-15 18:49:00) [32]На FireBird v1.5
CREATE TABLEOBJECTS(
ID VARCHAR(50) NOT NULL PRIMARY KEY, --Имя объекта
PARENT_ID VARCHAR(50) -- Объект родитель, NULL соответственно для TObject
);
CREATE TABLEPROPERTIES(
OBJECT_ID VARCHAR(50) NOT NULL FOREIGN KEY REFERENCESOBJECTS(ID), -- Объект, к которому относится свойство
ID VARCHAR(50) NOT NULL PRIMARY KEY, -- Имя свойства
PROP_VALUE VARCHAR(255) -- Значение свойства
);
CREATE PROCEDUREGET_OBJECT_PROP( -- Получает список свойств по имени объекта по иерархии
Q_OBJECT_ID VARCHAR(50) -- Имя объекта
) RETURNS(
OBJECT_ID VARCHAR(50), -- Объект, от которого унаследовано свойство
ID VARCHAR(50), -- имя свойства
PROP_VALUE VARCHAR(255) -- занчение
) AS
BEGIN
OBJECT_ID = :Q_OBJECT_ID;
WHILE(:OBJECT_ID IS NOT NULL) DO
BEGIN
FOR
SELECTP.ID, P.PROP_VALUE
FROM PROPERTIES P
WHERE(P.OBJECT_ID = :OBJECT_ID)
INTO :ID, :PROP_VALUE
DO
SUSPEND;
SELECT FIRST1 O.ID FROMOBJECTS O WHERE(O.PARENT_ID = :OBJECT_ID) INTO:OBJECT_ID;
END
END
Соответсвенно, вызов
SELECT * FROM GET_OBJECT_PROP('TMyObject') ORDER BY ID;
Ega23 (2007-01-15 18:38:00) [33]Мы с Alkid'ом следующую реализацию сделали:
1. Есть "деревянная" таблица Classes (ClassID, ParClassID, ClassName, Тип абстрактный/нет, ClassTableName, ClassSPName (только для реальных классов), остальные свойства)
2. К ней дочерними таблицами идут: ClassFields (ID, ClassID (для какого класса), OrgClassID (от какого класса унаследовано), FieldTypeID, FieldName); ClassEvents, ClassMethods.
3. Каждый неабстрактный класс имеет собственную таблицу с именем, указанном в Classes и с полями, перечисленными в ClassFields для данного ClassID.
Фактически, каждая запись в таблице реального класса - суть экземпляр объекта, а значения его полей - это его свойства.
Ну и всё это дело обёрнуто системой SP.
Johnmen (2007-01-15 18:37:00) [34]
> jack128 © (15.01.07 18:30) [3]
> В смысле?? Это иерархия классов, а не объектов.
Ну для БД то какая разница, как это называть? Или от названия что-то принципиально различно с т.з. БД?
По первому нет возражений. Разве что поля для каждого класса будут обозначать что-то именно ему присущее. Тогда их кол-во = макс. количеству св-в к.-л. класса. Соот-но разрежение минимально...
jack128 (2007-01-15 18:30:00) [35]Johnmen (15.01.07 18:08) [2]
Если у чилдов есть свои чилды, то м.б. стОит посмотреть на деревянную структуру, впихнутую в одну таблицу.
В смысле?? Это иерархия классов, а не объектов. И потом как разные классы в одну таблицу запихать? Либо вариант A, либо общие свойства в отдельные поля таблицы, а остально в блоб пихнуть.. А внуков у TParent нету.
Johnmen (15.01.07 18:08) [2]
Если нет, то однозначно "нарисовать доп. таблицу".
Хм. "По хорошему" наверно так и надо.. Но геморойно оно как то...
А есть по первому варианту возражения - если учесть, что кол-во полей <20 и расширение маловероятно?
Johnmen (2007-01-15 18:08:00) [36]Если у чилдов есть свои чилды, то м.б. стОит посмотреть на деревянную структуру, впихнутую в одну таблицу.
Если нет, то однозначно "нарисовать доп. таблицу".
jack128 (2007-01-15 18:01:00) [37]FB1.5, если это что то даст :-)