Проектирование базы данных SQL для представления иерархии классов OO - PullRequest
15 голосов
/ 05 августа 2010

Я в процессе преобразования иерархии классов для хранения в базе данных SQL.

Оригинал псевдо код:

abstract class Note
{
   int id;
   string message;
};

class TimeNote : public Note
{
   time_t time;
};

class TimeRangeNote : public Note
{
   time_t begin;
   time_t end;
};

class EventNote : public Note
{
   int event_id;
};

// More classes deriving from Note excluded.

В настоящее время я 'У меня есть пара идей, как сохранить это в базе данных.

A.Храните все заметки в одной широкой таблице

Таблица будет содержать всю информацию, необходимую для всех классов, производных от Note.

CREATE TABLE t_note(
   id INTEGER PRIMARY KEY,
   message TEXT,
   time DATETIME,
   begin DATETIME,
   end DATETIME,
   event_id INTEGER
);

Будущие классы, производные от Note потребностьдобавить новые столбцы в эту таблицу.

B.Сопоставьте каждый класс с таблицей

CREATE TABLE t_note(
   id INTEGER PRIMARY KEY,
   message TEXT
);

CREATE TABLE t_timenote(
   note_id INTEGER PRIMARY KEY REFERENCES t_note(id),
   time DATETIME
);

CREATE TABLE t_timerangenote(
   note_id INTEGER PRIMARY KEY REFERENCES t_note(id),
   begin DATETIME,
   end DATETIME
);

CREATE TABLE t_eventnote(
   note_id INTEGER PRIMARY KEY REFERENCES t_note(id),
   event_id INTEGER
);

Будущие классы, производные от Note, должны создать новую таблицу.

C.Используйте нормализацию базы данных и VARIANT / SQL_VARIANT

CREATE TABLE t_note(
   id INTEGER PRIMARY KEY,
   message TEXT
);

CREATE TABLE t_notedata(
   note_id INTEGER REFERENCES t_note(id),
   variable_id TEXT, -- or "variable_id INTEGER REFERENCES t_variable(id)".
                     -- where t_variable has information of each variable.
   value VARIANT
);

Будущие классы, производные от Note, должны добавить новые variable_id.

D.Сопоставьте каждый конкретный класс с таблицей (вновь добавленной на основе текущих ответов)

CREATE TABLE t_timenote(
   id INTEGER PRIMARY KEY,
   message TEXT,
   time DATETIME
);

CREATE TABLE t_timerangenote(
   id INTEGER PRIMARY KEY,
   message TEXT,
   begin DATETIME,
   end DATETIME
);

CREATE TABLE t_eventnote(
   id INTEGER PRIMARY KEY,
   message TEXT,
   event_id INTEGER
);

Будущие классы, основанные на Note, должны создать новую таблицу.


Каким было бы наиболее логичное представление в SQL?
Есть ли лучшие варианты?

Ответы [ 7 ]

8 голосов
/ 05 августа 2010

В общем, я предпочитаю obtion "B" (то есть одну таблицу для базового класса и одну таблицу для каждого "конкретного" подкласса).

Конечно, у этого есть пара недостатков: прежде всего вам нужно объединить как минимум 2 таблицы, когда вам нужно прочитать полный экземпляр подкласса.Кроме того, «базовая» таблица будет постоянно доступна любому, кто должен работать с любым видом заметки.

Но это обычно допустимо, если у вас нет экстремальных случаев (миллиарды строк, требуется очень быстрое время отклика ии т. д.).

Существует третий возможный вариант: сопоставить каждый подкласс с отдельной таблицей.Это помогает разделить ваши объекты, но в целом требует больше усилий при разработке.

См. this для полного обсуждения.

(Что касается вашего решения "C", использующего VARIANT: я не могу комментировать достоинства / недостатки, потому что это выглядит как частное решение - что это такое? Transact-SQL? И я не знаком сэто).

3 голосов
/ 05 августа 2010

Ваш вариант «B», как описано, в значительной степени является реализацией «иерархии подклассов объектов» (Kung, 1990 http://portal.acm.org/citation.cfm?id=79213)

)

Как таковой, это хорошо разработанный и понятный метод. Это работает довольно хорошо. Он также распространяется на несколько уровней наследования, если вам это нужно.

Конечно, вы теряете некоторые преимущества инкапсуляции и сокрытия информации, если не ограничиваете доступ к данным через интерфейс СУБД.

Однако вы можете получить к нему доступ из нескольких систем и даже языков одновременно (например, Java, C ++, C #) (Это была тема моей магистерской диссертации:)

2 голосов
/ 07 августа 2010

Вы выбрали 3 наиболее распространенных способа моделирования объектов в реляционной базе данных. Все 3 приемлемы, и у каждого есть свои плюсы и минусы. К сожалению, это означает, что нет правильного «правильного» ответа. Я реализовал каждый из них в разное время, и вот несколько замечаний / предостережений, о которых следует помнить:

Опция A имеет недостаток, заключающийся в том, что при добавлении нового подкласса необходимо изменить существующую таблицу (это может быть менее приемлемым для вас, чем добавление новой таблицы). Недостатком также является то, что многие столбцы будут содержать значения NULL. Однако современные БД выглядят НАМНОГО лучше в управлении пространством, чем старые БД, поэтому я никогда не беспокоился о нулях. Одним из преимуществ является то, что ни одна из ваших операций поиска или получения не потребует JOIN или UNION, что потенциально повышает производительность и упрощает SQL.

Опция B имеет недостаток, заключающийся в том, что если вы добавляете новое свойство в ваш суперкласс, вам необходимо добавить новый столбец в каждую таблицу каждого подкласса. Кроме того, если вы хотите выполнить гетерогенный поиск (все подклассы одновременно), вы должны сделать это с помощью UNION или JOIN (потенциально более низкая производительность и / или более сложный sql).

Опция C имеет недостаток, заключающийся в том, что все операции поиска (даже для одного подкласса) будут включать JOIN, как и большинство поисков. Кроме того, все вставки будут включать несколько таблиц, что делает несколько более сложным SQL и потребует использования транзакций. Этот вариант представляется наиболее «чистым» с точки зрения нормализации данных, но я редко использую его, потому что недостаток JOIN-для-каждой-операции обычно делает один из других вариантов более приемлемым.

1 голос
/ 05 августа 2010

Я бы с благодарностью отнесся к варианту А.

Это также немного зависит от ваших сценариев использования, например, вам нужно будет выполнить много поисков по всем типам заметок?Если да, то вам лучше использовать вариант A.

Вы всегда можете сохранить их как вариант A (одна большая таблица) и создавать представления для различных вложенных примечаний, если хотите.Таким образом, вы все равно можете иметь логическое разделение при хорошей возможности поиска.

В целом, но это может быть близко к религиозному обсуждению, так что будьте осторожны, я считаю, что реляционная база данныхреляционная база данных, а не пытаться имитировать ОО-структуру.Пусть ваши классы делают OO, пусть db будет реляционным.Существуют специальные базы данных ОО, если вы хотите расширить это до своего хранилища данных.Это означает, что вы должны пересечь «Несоответствие объектно-реляционного импеданса», как они его называют, но опять же есть ORM-преобразователи для этой конкретной цели.

0 голосов
/ 30 декабря 2018

Я знаю, что этот вопрос старый, но у меня есть другой вариант:

В любом столбце таблицы (текстовый тип) можно сохранить объект Note или коллекцию объектов Note в виде структуры json.Вы можете сериализовать и десериализовать JSON, используя Newtonsoft .Вам нужно будет указать параметры обработки имени типа для объекта для JsonSerializer .

0 голосов
/ 28 июля 2012

Я бы пошел на вариант A .

Решение B хорошо, если иерархия классов очень сложна, когда десятки классов наследуют друг друга. Это самое масштабируемое решение. Однако недостатком является то, что он делает SQL более сложным и медленным.

Для относительно простых случаев, например, когда 4 или 5 классов наследуют один и тот же базовый класс, более разумно выбрать решение A. SQL будет более простым и быстрым Затраты на дополнительные столбцы со значениями NULL незначительны.

0 голосов
/ 05 августа 2010

Существует серия паттернов, известных под общим названием «Пересекающиеся пропасти», которые я использовал много лет. Не позволяйте ссылкам на Smalltalk бросить вас - это применимо к любому объектно-ориентированному языку. Попробуйте следующие ссылки:

Язык шаблонов для реляционных баз данных и Smalltalk
Пересекающиеся пропасти - Статические паттерны
Пересекающиеся пропасти - архитектурные узоры

Делись и наслаждайся.

EDIT

Wayback Machine ссылается на все, что я смог найти в паттернах Crossing Chasms: http://web.archive.org/web/20040604122702/http://www.ksccary.com/article1.htm http://web.archive.org/web/20040604123327/http://www.ksccary.com/article2.htm http://web.archive.org/web/20040604010736/http://www.ksccary.com/article5.htm http://web.archive.org/web/20030402004741/http://members.aol.com/kgb1001001/Chasms.htm http://web.archive.org/web/20060922233842/http://people.engr.ncsu.edu/efg/591O/s98/lectures/persistent-patterns/chasms.pdf http://web.archive.org/web/20081119235258/http://www.smalltalktraining.com/articles/crossingchasms.htm http://web.archive.org/web/20081120000232/http://www.smalltalktraining.com/articles/staticpatterns.htm

Я создал документ Word, который объединяет все вышеперечисленное в нечто, похожее на единое целое, но у меня нет сервера, на котором я могу разместить его, чтобы сделать его общедоступным. Если кто-то может предложить бесплатное хранилище документов, я был бы рад разместить документ там.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...