Рекомендации по проектированию данных - PullRequest
1 голос
/ 25 января 2010

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

В основном, у меня есть некоторые сущности, подобные следующим:

Лицо, контакт, родитель

И контакт, и родитель - это люди. Человек может быть контактом, родителем, обоими или ни тем, ни другим.

В структуре базы данных, которую я придумал, есть таблица для каждой из этих трех сущностей, и все три таблицы имеют общий идентификатор (PersonID). С точки зрения проектирования базы данных это, по-видимому, хорошо нормализованный и достаточно эффективный способ представления базы данных и ее взаимосвязей (по крайней мере, для меня).

С этого момента я начинаю кодировать классы C # и отображения NHibnerate для представления этих объектов. Самый естественный подход к отображению, который я могу найти, - это использовать отображение. Другие параметры (один-к-одному, один-ко-многим и т. Д.), По-видимому, требуют добавления одного или нескольких ненужных FK в таблицы. Просматривая документацию NHibernate, я натыкаюсь на следующее утверждение:

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

Мой вопрос:

А) Я нарушаю этот принцип? Б) Если да, то как мне лучше спроектировать эту систему?

Предполагает ли это утверждение, что я должен объединить все поля Person / Contact / Parent в одну таблицу (со многими обнуляемыми полями)? Или я как-то упускаю суть?

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

Изменить: Подробнее о том, как я планирую работать с вышеуказанным дизайном базы данных:

Основная идея заключается в том, что каждый человек получает запись в таблице персон. Наличие / отсутствие записей в связанных таблицах определяет, является ли человек родителем, контактом и т. Д. Это, по-видимому, обеспечивает соблюдение отношений one-> one и позволяет выполнять быстрые запросы / объединения (общий первичный идентификатор будет кластерный ПК в каждой таблице).

Редактировать: Спасибо за помощь, ребята. На самом деле, я не очень хорошо разбирался в вопрососпособности запросов, когда разрабатывал эту систему, поэтому собираюсь перейти к чему-то похожему на решения, предложенные Jamie Ide & hlgem. Я нашел все ответы полезными. В целом, похоже, что общие первичные ключи приводят к некоторым проблемам с объектной моделью на стороне c #.

Ответы [ 3 ]

2 голосов
/ 25 января 2010

Ваша база данных требует немного работы; вот мое предложение.

Хорошо, что у вас есть идея, что Контакт и Родитель оба могут быть Лицами; однако для контакта и родителя необходимо иметь разные первичные ключи. Вы можете применить требование, чтобы у них обоих были родительские идентификаторы с необнуляемым внешним ключом в таблицах Контакт и Родитель, который ссылается на личный идентификатор записи в таблице Персона.

Таким образом, таблица Person должна иметь уникальный первичный ключ (его идентификатор) и любые другие соответствующие столбцы. Таблица контактов должна иметь свой собственный уникальный первичный ключ (его ID), необнуляемую ссылку внешнего ключа на таблицу Person (идентификатор в таблице Person) и любые другие соответствующие столбцы. Родительская таблица должна иметь свой собственный уникальный первичный ключ (его ID) и необнуляемую ссылку внешнего ключа на таблицу Person (идентификатор в таблице Person) и любые другие соответствующие столбцы.

Это должно решить ваши проблемы с отображением. Если вам нужно, вы можете использовать View для «рекомбинации» вашего «созвездия» Персона / Родителя / Контакта (коллекция связанных таблиц).

1 голос
/ 26 января 2010

Отчасти это зависит от того, как вы собираетесь запрашивать эти данные. Если вы хотите легко увидеть, какие роли играет человек, без подробностей, относящихся к роли, то создайте таблицу ролей. Чтобы увидеть все роли, которые есть у человека, нужно объединить только две таблицы, независимо от того, сколько ролей вы добавите позже. В противном случае вам придется присоединиться к каждой из специальных таблиц (оставленные объединения, если они не существуют), чтобы посмотреть, какие роли выполняет человек. Не очень хорошо для производительности.

У нас есть много таких типов отношений в нашей базе данных, и у нас есть таблица персон с идентификатором, таблица ролей с идентификатором и идентификатором роли в ней и таблица типа роли, которая представляет собой поиск ролей. А затем специальные таблицы, содержащие информацию для конкретной роли, например, торговые представители или цели продаж. Каждая таблица имеет свой собственный идентификатор, и каждая таблица (кроме таблицы поиска) содержит идентификатор из таблицы person, которая установлена ​​как внешний ключ. (Поверьте мне, очень редко встречается такая вещь, как ненужные внешние ключи, обратное утверждение неверно, пропуская FK, когда он у вас должен быть, - плохая новость.)

Теперь вы все еще можете иметь отношение внешнего ключа, используя только PK из родительской таблицы в качестве Fk для таблицы person и PK таблицы специальности, но я рекомендую против этого. В любом случае, если вы не настроили FK для таблицы person, ваши данные обречены на проблемы с целостностью данных. Я предпочитаю использовать суррогатные ключи и поэтому всегда устанавливаю свой собственный ключ на каждую таблицу. Это предотвращает многие проблемы перепроектирования в долгосрочной перспективе. Если вы хотите поддерживать взаимно-однозначное отношение, все, что вам нужно, - это простой уникальный индекс на поле. Таблица перемещается от одного к одному до одного ко многим, и все, что вам нужно сделать, это сбросить индекс. Если вы также использовали его в качестве своего PK, то вам нужен новый PK, и весь код, ссылающийся на pk, должен быть изменен. Добавление нового ПК в таблицу с 150 000 000 записей - не веселая задача.

1 голос
/ 25 января 2010

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

Если вы придерживаетесь подклассов, я бы порекомендовал придерживаться таблицы на класс , если это возможно.

Но лучшим вариантом может быть введение таблицы «ролей» и наличие отношений «один ко многим» между человеком и ролью.

Отредактировано, чтобы добавить: IMHO, ваш текущий дизайн не будет работать. Какой тип объекта будет представлять человека, который является одновременно контактом и родителем?

Вместо простой таблицы ролей вы могли бы использовать «сложные» таблицы ролей, которые включали дополнительные данные. Вы можете иметь набор объектов Role (ContactRole, ParentRole и т. Д.), Каждый из которых содержит поля, связанные с этой ролью. Затем объект Person будет иметь коллекцию объектов Role.

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