2013-05-08 12 views
2

Это не совсем отношения «многие ко многим». Например: У меня есть таблица пользователей и таблица ролей. Ограничение: пользователь может иметь 0-5 ролей, а роль может быть назначена для многих пользователей.Как моделировать отношения «несколько ко многим» в базе данных?

Как смоделировать это в базе данных? Спасибо

EDIT: Я ищу стандартное решение на стороне базы данных для этой модели. Существуют аналогичные сценарии, подобные описанным выше. Например: история паролей пользователей: У одного пользователя будет максимально 10 предыдущих паролей, хранящихся в таблице pwd_history. Это своего рода отношение к одному (0-10).

Но, похоже, стандартного решения на стороне базы данных нет. (Решение @ Branko (2) ниже выглядит неплохо.) Я думаю, что лучшей практикой для этой модели является обеспечение соблюдения на стороне клиента, что делает эти номера настраиваемыми в файле свойств и реализующими клиентскую логику для обработки этого.

+1

Из любопытства, какова цель ограничения роли до 5 максимум? Если это всего лишь общее количество ролей, это не так много, как многие из многих, в отличие от жесткого ограничения на какое-то число. – jefflunt

+0

Ха, я думаю, вы имеете в виду «многих ко многим»? –

ответ

2

Создать таблицу UserRoles

UserRoleID PK 
UserID  FK 
RoleID  FK 

Вы должны следить за соблюдением 5 ролей ограничение с триггером INSERT (пример here), или в бизнес-логики приложения.

0

Возможно, это не нормализованный дизайн, но для небольшого количества ролей вы можете просто добавить 5 столбцов с нулевым значением для пользователя, role1, role2 и т. Д., Хотя это может усложнить обновление.

+0

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

+1

Не будет ли этот запрос работать? выберите * от пользователей, где userId = 1 и (role1 = 1 или role2 = 1 ...) и т. д. Также вы всегда можете извлечь всю запись на сервер и проверить там. – Alexander

+0

Конечно. Но что, если пользователю назначено менее пяти ролей, и вы должны добавить его? Вам понадобится логика, чтобы найти пустой слот. –

1

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

0

Я не использовал его в БД, но при использовании в c языке для других целей, я следил за этим методом.

Рассмотрим Role1, роль2 ... Role5

Role => Bit-Pattern => Number 
------------------------------- 

Role1 => 00000001 => 2 
Role2 => 00000010 => 4 
Role3 => 00000100 => 8 
Role4 => 00001000 => 16 
Role5 => 00010000 => 32 

Поддерживайте один столбец называется roles в БД. И следить за этим,

Role1 + Role2 ==> 2 + 4 ==> 6 
Role1 + Role2 + Role5 ==> 2 + 4 + 32 ==> 38 
Role3 + Role4 ==> 8 + 16 ==> 24 

Таблица будет содержать только 38 для пользователя Role1 + Role2 + Role5.

Так, чтобы проверить, если пользователь имеет роль role3, сделать как Role3 ==>role_col ИЛИ Role3 т.е. (role_column || 8) будет возвращена истина.

Это экономит новый стол; может содержать разные числа до количества бит в поле (8 здесь 8 бит = 1 байт); Один простой запрос без соединения.

+0

Что делать, если есть более 32 или 64 ролей? – Alexander

+0

Вам нужна только 32 или 64-битная ширина. поэтому 8-байтовый максимум здесь. – VoidPointer

+2

Извините, но это, вероятно, плохая идея. Вы нарушаете принцип [атомарности] (http://en.wikipedia.org/wiki/1NF#Atomicity) и, следовательно, 1NF. Как следствие, СУБД не может поддерживать ссылочную целостность для вас, и у вас возникнут проблемы с индексацией и, следовательно, с эффективным запросом на это «растровое изображение». Другие уже указали, что общее число ролей будет ограничено таким образом. Если вы можете жить со всем этим (например, потому что роли очень мало и полностью статичны), то это может быть очень компактным и быстрым решением, но это не общее решение. –

4

Есть 3 стратегии:

  1. Только модели как обычный многие-ко-многим в базе данных, но следить за соблюдением лимита в триггерах или (менее в идеале) код клиента.

  2. модель это как многие-ко-многим, но разместить дополнительные ограничения, чтобы ограничить количество строк:

    enter image description here

    CHECK (ROLE_NO IN (1, 2, 3, 4, 5))

    Сочетание уникального ограничения U1 на {USER_ID, ROLE_NO} а выше CHECK гарантирует, что не может быть более пяти строк USER_ROLE, принадлежащих одному пользователю.

  3. Просто пять NULL-состоянии 1-ко-многим:

    enter image description here


Из всех этих стратегий, мой первый инстинкт должен был бы пойти (2) - это, пожалуй, «самый чистый» и легко поддается изменению, если ваши пределы когда-либо изменятся.

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

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

+0

Я не уверен, что понимаю ваш второй пример. Я предполагаю, что вы уже поставили число от 1 до 5 в ROLE_NO, так когда это когда-нибудь будет шесть? Ваше ограничение уже выполнено, пока это не так, и теперь у вас слишком много записей в группе. Как вы получаете следующий ROLE_NO в группе? Нужно ли сначала запрашивать базу данных? –

+0

@RobertHarvey Извините, я не понимаю, что вы подразумеваете под «слишком большим количеством записей в группе». СУБД всегда будет использовать оба ограничения, поэтому у вас никогда не будет более 5 строк на пользователя. Что касается запроса - это зависит. Если клиент уже знает, какие «слоты» он взял, тогда может быть необязательно запрашивать базу данных (в зависимости от одновременных клиентов). В противном случае создание такого запроса достаточно просто, особенно если ваша СУБД поддерживает аналитические функции. Даже с запросом это не обязательно означает дополнительную базу данных в оба конца, если она помещена в триггер. –

+0

Я могу купить аргумент о том, что вы можете создать аналитическую функцию в базе данных для этого, но не для того, чтобы клиент имел необходимые знания для выполнения вставки или должен был предварительно загрузить все существующие роли. Действительно, база данных должна нести полную ответственность; клиент должен иметь возможность передать базе данных новую User + Role, и она будет либо успешной, либо неудачной по существу. –

Смежные вопросы