Нормализация внешних ключей с помощью таблиц соединений и поиска - PullRequest
0 голосов
/ 12 июля 2011

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

В настоящее время у меня есть следующие таблицы: Users, UserTypes, Roles, UsersInRoles и Permissions. UserTypes - это просто справочная таблица, предоставляющая имя типа с описанием через внешний ключ в таблице Users. Роли - это различные роли со связанными разрешениями, связанными с каждым пользователем через таблицу UsersInRoles.

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

У меня был внешний ключ к моей таблице UsersInRoles из таблицы Users, но я решил, что это просто не имеет смысла. И наоборот, представляется целесообразным использовать внешний ключ из таблицы Users в таблицу UserTypes. Это эмпирическое правило? Что у соединительных таблиц есть внешние ключи, связывающие с первичными ключами таблиц, к которым они присоединяются, в то время как у главных таблиц есть внешние ключи, связывающие с первичным ключом связанных таблиц поиска?

Параметры:

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

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

ОБНОВЛЕНИЕ
Это в основном, как это было бы настроить? Я мог бы избавиться от таблицы UsersInRoles, чтобы каждый пользователь мог играть только одну роль, а дополнительные разрешения могут быть добавлены через таблицу соединений SpecialPermissions. С точки зрения пользовательского интерфейса, я подумал, что было бы хорошо при назначении разрешений пользователю: выбор «Роли» просто установит соответствующие флажки, связанные с этой ролью, затем вы настроите это и отправите. Таким образом, я думаю, что мне понадобится только таблица соединений между таблицами Users и Permissions? Тьфу. Это довольно сложно впервые для разработчиков баз данных, ха-ха. Помнишь, когда ты только начинал? Или, может быть, вы, ребята, больше гений, чем я, lol.

Схема Ссылка на изображение (пока нельзя публиковать изображения)

Вот аккуратная научная статья (хотя и 10 лет) о разработке баз данных на основе запросов: « Надежный дизайн баз данных для различных шаблонов запросов ». В разделе «Заключение» есть интересный подход.

Ответы [ 3 ]

1 голос
/ 12 июля 2011

Я подозреваю, что мне также может понадобиться таблица соединений PermissionsInRoles. как один для PermissionsInUsers?

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

Table: role_permissions
PK:    (Role, Permission)

Role    Permission
--
User    Create
User    Update
Admin   Create
Admin   Update
Admin   Delete

Вам не нужно две разные таблицы для реализации этого требования.

К тому же, вы уже сказали: «У каждого пользователя могут быть дополнительные разрешения, не предоставляемые их ролями». Чтобы выполнить это требование, вы должны хранить пользовательские разрешения.

Table: user_permissions
PK:    (username, permission)

username    permission
--
user1       Rename
user1       Leak to News of the World
user2       Randomly corrupt data

Итак, опять же, вам не нужны две разные таблицы для реализации этого требования. Обе эти таблицы в 5NF.

Но это просто смешно, не так ли?

Что смешного?

  • Что у вас очень сложные требования к разрешениям?
  • Что вы храните бизнес-данные (например, разрешения) в таблицах?
  • Что требуется более одной таблицы для моделирования ваших требований к разрешениям?
  • Что-то еще?

Если вам нужен конкретный совет относительно ваших реальных таблиц, отредактируйте свой вопрос и вставьте DDL для своих таблиц.


Позже

Я посмотрел на вашу диаграмму. Не каждой таблице нужен идентификационный номер; Идентификационные номера не имеют ничего общего с нормализацией.

Если бы я проектировал вашу систему, я бы, вероятно, не использовал номера идентификаторов в таблицах Roles, Permissions и UserTypes, пока не увидел проблему с производительностью, которую можно исправить с помощью номеров id. (В большинстве систем за последние 30 лет это означает, ну, почти никогда.) Прежде чем я использовал идентификационный номер, я бы также рассмотрел и протестировал использование удобочитаемого кода. Читаемые человеком коды часто не требуют соединений; Идентификационные номера всегда требуют соединений.

В большинстве баз данных SQL вы можете комбинировать тип данных и проверять ограничение в операторе CREATE DOMAIN. В PostgreSQL вы можете использовать что-то подобное, чтобы уменьшить количество таблиц.

CREATE DOMAIN role AS VARCHAR(7) NOT NULL
  CHECK (VALUE in ('Admin', 'User', 'Guest'));

Вслед за

CREATE TABLE user_roles (
  user_id integer not null references users (id),
  role_name role 
);

Замена таблицы оператором CREATE DOMAIN наиболее полезна, когда число строк стабильно и относительно мало. Лично я бы предпочел таблицы.

Если вы придерживаетесь идентификационных номеров, вам также нужны уникальные ограничения для Roles.RoleName, Permissions.Description и UserTypes.UserType.

В остальном у вас вроде все нормально.

0 голосов
/ 12 июля 2011

Если ваши защищаемые продукты являются просто таблицей продуктов (или набором таблиц), и вы используете SSMS (SQL-Server Management Studio), то вам не следует изобретать собственную схему безопасности с нуля.

Я бы порекомендовал вам настроить пользователей и роли в SSMS - разверните базу данных, затем -> Безопасность -> Пользователи и т. Д. Щелкните правой кнопкой мыши пользователя, найдите защищаемые элементы, а затем вы можете назначить пользователь для ролей, а также, просто объекты (таблицы и т. д.) напрямую. Или щелкните правой кнопкой мыши по ролям, и у вас появятся похожие варианты. Что бы вы ни делали, держитесь подальше от создания собственной схемы безопасности, если вы можете ей помочь.

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

0 голосов
/ 12 июля 2011

Одна вещь, которую я сделал раньше, в похожем сценарии:

Сохранение ролей и пользователей в одной таблице.

Наличие таблицы объектов (таблиц / запросов / форм)/ etc. вам будут предоставлены разрешения)

Иметь таблицу разрешений - здесь вы можете связать роли / пользователей с объектами (т. е. Джон может выбрать SELECT в таблице 1)

Наконециметь таблицу наследования - здесь вы будете связывать роли / пользователей друг с другом (т. е. у Джона есть разрешение делать все, что может делать Role1)

Например, такая структура:

Например:

Users Table:
UserID -- User -- UserTypeID
1 ------- John Smith --- 1
2 ------- Sally Fort --- 1
3 ------- Public Role -- 2
4 ------- Special Role - 2

UserType Table:
UserTypeID -- Description
1 ----------- Human Being
2 ----------- Role

Objects Table:
1 -- Data-Entry Form 1
2 -- Data-Entry Form 2
3 -- Query 1
4 -- Table 1

Permissions Table
UserID -- ObjectID -- Permission
1      -- 1        -- Update (This says John can Update Data-Entry Form 1 (via direct permission))
3      -- 1        -- Update (This says that the Public Role can Update Data-Entry Form 1)
3      -- 2        -- Update (...as well as Data-Entry Form 2)
4      -- 3        -- Select (This says that the special role can Select from Query1)
4      -- 4        -- Insert (...the special role can Insert into Table1)

Permission Inheritance Table
UserID -- UserID_ToInheritFrom
1      -- 3 (this says John can do whatever the Public Role can do)
1      -- 4 (this says John can do whatever the Special Role can do)
2      -- 3 (this says Sally can do whatever the Public Role can do)

Итак, если вы хотите задать вопрос: «Что может сделать Джон?», Вы сделаете что-то вроде этого:

SELECT
   ObjectID,
   Permission
FROM
   PermissionsTable
WHERE
   UserID = 1 -- John has direct permission
   OR UserID IN (SELECT UserID_ToInheritFrom FROM PermissionInheritanceTable WHERE UserID = 1)
   -- John has indirect permission via the Permission Inheritance Table (or you can call it the "role
   -- membership table" if that's easier for you to think of that way.)

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

...