Схема базы данных, которая может поддерживать специализированные свойства

Мне нужно хранить набор сущностей, из которых есть несколько специализированных версий. У них есть некоторые общие свойства, но специализированные содержат свойства, специфичные для этой сущности.

Решения

Хранилище данных - это реляционная СУБД, и это не для обсуждения:-) В частности, это Microsoft SQL Server 2005.

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

Другая идея состоит в том, чтобы создать таблицу

reading(<common properties>, extended_properties)

и иметь extended_propertiesполе будет своего рода сериализации расширенных свойств. Я думал о JSON или XML. Скорее всего, я буду использовать каркас ORM, но я еще не решил. В любом случае, объектное представление специализированного объекта из reading может выставить словарь {extended_property_name, value} содержит проанализированные пары ключ / значение из extended_properties поле.

Из этого http://msdn.microsoft.com/en-us/library/ms345117(SQL.90).aspx я понял, что поля XML в сочетании со схемами для них дают представление о типизированном XML внутри СУБД. Кроме того, запросы, включающие содержимое XML в extended_propertiesполе может принять это во внимание, тоже.

Что я хочу

Отзывы о моих предложениях по решению, в первую очередь с reading таблица и сериализация расширенных свойств.

Кроме того, я понимаю, что это одно из ограничений реляционных СУБД по сравнению с хранилищами на основе ключа / значения. Однако, безусловно, должны быть некоторые методы моделирования, чтобы приспособиться к этому.

Любая обратная связь с благодарностью!

5 ответов

Решение

Андерс, не отказывайся ни от какой целостности или твердости, например, от типовой безопасности.

(Ответ приходит).

@Anders. Нет, совсем нет, подтип - это хорошо (вопрос в том, какую форму вы используете и каковы недостатки / преимущества). Не отказывайтесь ни от силы, ни от целостности, ни от безопасности, ни от проверок, ни от DRI. Форма, которую вы выберете, потребует дополнительных проверок и, возможно, небольшого количества кода (зависит от вашей платформы).

Этот вопрос часто поднимается, но у искателя всегда узкая перспектива; Я продолжаю делать одни и те же утверждения (подмножество) из неизменного набора. Идея состоит в том, чтобы оценить все варианты. Итак, я пишу документ. К сожалению, это занимает больше времени. Возможно 4 страницы. Не готов к публикации. Но диаграммы закончены, я думаю, что вы находитесь на высоте, и вы можете использовать его прямо сейчас.

Предупреждение: только опытные инженеры-строители проекта
Дорога не подходит для караванов или читателей с высоким коэффициентом Eek

Ссылка на ▶ Четыре альтернативных модели данных ◀ в Документе на стадии разработки. Извиняюсь за беспорядок на полу; Я скоро уберусь.

▶ Ссылка на нотацию IDEF1X ◀ для всех, кто не знаком со Стандартом моделирования реляционных баз данных.

  1. Все они реляционные, с полной целостностью.

  2. Варианты 6NF. Реляционный сегодня (SQL) не обеспечивает поддержку 6NF; он не запрещает этого, он просто не обеспечивает структуры 5NF➔6NF. Поэтому вам нужно создать небольшой каталог, который некоторые люди называют "метаданными". На самом деле, это просто расширение стандартного каталога SQL (таблицы sys). Требуемый уровень контроля моделируется в каждой опции.

  3. По сути, EAV выполнен правильно, с полным контролем и целостностью (безопасность типов, декларативная ссылочная целостность и т. Д.), А не с беспорядком, как обычно.

Вас могут заинтересовать следующие связанные вопросы / ответы (в частности, посмотрите на Модели данных):

Несколько фиксированных и абстрактных гибких

Проблема, связанная со схемой базы данных

"Простая" проблема проектирования баз данных

Ответ на комментарии

... Таким образом, мы можем легко получить строки "Комментарий", связанные с данным экземпляром специализированного типа. Это способ сделать это, или я буду сожалеть об этом решении позже? Есть ли какой-то другой шаблон, который мы пропустили?

Не уверен, что вы имеете в виду. Комментарии, заметки, адреса в конечном итоге используются (резидентные столбцы) во многих таблицах, поэтому правильный метод - нормализовать их; предоставить одну таблицу для комментариев; на который ссылаются из любой таблицы, которая этого требует. Вот общая таблица комментариев. Он используется в Product (супертип), потому что вы указали любой Product. С таким же успехом его можно использовать в некоторых подтипах Product, но не в других; в этом случае FK будет в указанных подтипах продукта.

Ваша модель данных

Какова цель таблицы ProductType в вашем примере Product 5NF/subtype? Содержит ли он строку, соответствующую каждому специализированному продукту, например ProductCPU? Я предполагаю, что это указывает на специализацию базового продукта.

(Исправлена ​​небольшая критическая ошибка на диаграмме.)

Да, точно.

В стандартных реляционных терминах (а не неконтролируемые беспорядки, выдаваемые за базы данных), ProductType является Discriminator; он определяет, какой из подтипов продукта применяется к данному продукту. Сообщает вам, к какой таблице подтипов продукта вы должны присоединиться. Пара вместе составляет логичный продукт. Не забудьте создать виды, по одному на каждый тип продукта.

  • (Оцените, как изменяется ProductType, какую именно роль он играет для каждой из четырех моделей данных.)

  • "Обобщение-специализация" - все это mumbo jumbo, терминология OO; не переступая черту и не узнавая, на что способен Relational в течение 30 лет. Если вы немного узнаете о Реляционном, вы получите полную силу; в противном случае вы ограничены очень ограниченным подходом ОО ко всему (Амблеру и Фаулеру есть за что ответить). Пожалуйста, прочитайте этот пост с 11 декабря по 10 и далее. Модель реляционных баз данных Сущности, а не объекты; не классы.

Например, при добавлении нового продукта вы хотите предоставить, скажем, выпадающий список типов продуктов, которые можно добавить. На основании этого выбора можно определить, в какие таблицы следует помещать данные. Правильно? Прошу прощения за разговор о коде приложения, но мне просто нужно представить его в перспективе

Да. И какую страницу (с полями) предоставить дальше, чтобы пользователь вводил данные.

Нет проблем говорить о коде приложения, которое будет использовать Rdb, они идут вместе, как муж и жена (не муж и раб).

  • Для ваших классов OO сопоставьте дерево классов с Rdb, как только вы закончили моделирование Rdb, независимо от приложения, которое будет его использовать. А не наоборот. И не зависит от одного приложения.

  • Забудьте о "сохранении", у него много проблем (Потерянные обновления; поврежденная целостность данных; проблемная отладка; массовая конкуренция; и т. Д.). Все обновления Rdb должны быть в Транзакциях, с соответствием ACID, доступным в течение 30 лет, но Фаулер и Амблер еще не читали об этом. Обычно это означает, что один сохраненный протокол предварительно.

Дискриминант - это FK таблицы типов, как мы установили ранее. Это обозначает, какие спецификации. Подтип базового типа придерживается. Но что детализирует таблица дискриминантов?

Разве это не ясно из модели данных? ProducType CHAR(1) или же (2). Name Char(30),

Может быть удобным для отображения текстом с указанием типа для целей пользовательского интерфейса,

Да, среди прочего, такие как контроль, противопоказания и т. Д., Устранение двусмысленности при кодировании или отчетности.

но содержит ли оно также точное имя таблицы, которая содержит специализированный тип?

Нет. Это было бы слишком физически, чтобы помещать в данные. Запрещено в принципе.

Но это не обязательно.

Скажем, меня интересует Продукт с ID = 1. У него есть дискриминант, указывающий, что это ProductCPU. Как бы вы пошли извлекать этот ProductCPU из кода вашего приложения?

Это будет легко, если вы возьмете предоставленную модель и реализуете ее (все таблицы) как классы, правильно и т. Д. В примере, который вы запрашиваете, не будут использоваться представления (которые предназначены для списков и более общего использования). Псевдокод будет:

  • Учитывая ProductId (Подтип неизвестен, поэтому вы не должны находиться в окне, относящемся к подтипу), загрузите Product только супертип
  • на основе дискриминатора Product.ProductType, установите индикаторы и т. д. и загрузите соответствующий подтип, один из ProductCPU; ProductMemory; ProductDisk; ProductTape; и т.п.

  • Я видел (и не согласен с) ОО методы, которые загружают все подтипы для данного ProductId сразу: один подтип действителен; а остальные недействительны. Код все еще должен ограничивать себя действительным классом для Product основанный на Product.ProductType,

Поочередно, например. где контекст, пользователь сидит в специфичном для подтипа окне, например. ProductCPU, с этим классом, настроенным, и запросы ProductId ххх. Затем используйте ProductCPU Посмотреть. Если он возвращает ноль строк, он не существует.

  • Там может быть ProductDisk ххх, но не ProductCPU ххх. Как вы справляетесь с этим, независимо от того, указываете ли вы, что существует Product`xxx, но это не ЦП, или нет, это зависит от требований приложения.

Для списков, где приложение заполняет сетку, независимо от ProductId, используйте представления (по одному на каждом), чтобы загрузить каждую сетку. Этот SQL основан на объединении и не должен ссылаться на ProductType,

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

Причина: вы говорите, что ваша реализация будет выполнена в СУБД, и это не подлежит обсуждению. Хорошо. Вывод неструктурированных, похожих на BLOB-объектов вещей, таких как сериализованная хэш-таблица в поле БД, противоречит философии проектирования СУБД, поэтому вы сильно пострадаете от эффективности, если не согласитесь с идеей рассматривать поле * extended_properties * как непрозрачное BLOB, как GIF или другой двоичный объект.

Другими словами, забудьте (эффективно) запрашивать "все объекты, имеющие расширенное свойство COLOR=RED".

Ваша проблема (описание ОО-таксономий в СУБД) определенно не нова. Посмотрите на это, для подробного описания вариантов.

Это классический пример шаблона проектирования Gen-Spec. Gen-spec рассматривается в каждом уроке по объектному моделированию, потому что он обрабатывается наследованием. Это часто пропускается в руководствах по моделированию реляционных данных. Но это хорошо понято.

Провести веб-исследование на тему "Обобщение специализации реляционного моделирования". Вы увидите несколько статей о том, как настроить одну таблицу для общего класса и таблицу для каждого специализированного класса. Статьи помогут вам с дизайном внешнего ключа. В частности, первичный ключ каждой специализированной таблицы выполняет двойную функцию. Это также внешний ключ к обобщенной таблице.

Это не покажется вам знакомым, если вы привыкли к объектному моделированию. Но вы обнаружите, что это работает хорошо. И решение, предлагаемое в большинстве статей, не является динамическим, поэтому вам придется выполнять некоторые DDL каждый раз, когда обнаруживается новый специализированный подкласс.

Вот пять примеров из SO. Какой из них использовать, зависит от конкретной проблемы, которую вы решаете, и ваших предпочтений.

Вообще я бы не советовал сериализовать данные в поля БД.

Если существует относительно немного специализированных версий сущности, вы можете просто использовать подтипирование, как в следующих примерах: пример первый, пример два.

Для больших значений свойств или если свойства должны быть определены динамически (без изменений схемы), посмотрите на реализацию схемы наблюдения, как в следующих примерах: пример три, пример четыре; или в так называемую шестую нормальную форму, как описано в примере пять. Обратите внимание, что "схема наблюдения" является упрощенной версией 6-й НФ.

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

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

Unique_Property_ID
, FK_To_Some_Entity (Not sure what entity these link to: customers, bills, etc.) 
, Property_Type Not the data type but a link to a table describing this entity)
, Property_Value (Difficult to determine if all of your values will be of the same type: string, int, date, etc.)

Пример: автосалон подержанных автомобилей, которому нужно отслеживать надстройки для разных марок и моделей (они никогда не знают, что они получат). Несколько записей могут выглядеть так:

VehicleID   Property Type  Property Value
3           Sound System   Bose
3           Hybrid System  Battery
7           Starter Type   Hand Crank
7           Passenger Seat Rumble
9           Starter Type   Kick Start
9           Passenger Seat Side Car

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

Другая проблема заключается в том, что если вы хотите, чтобы каждое свойство было представлено в виде столбца, вам нужно будет транспонировать эту таблицу.

Другие вопросы по тегам