Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Иерархия объектов в БД


Страницы:   1 2

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
    SELECT
P.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
     SELECT
P.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, если это что то даст :-)


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо