Я разрабатываю систему, которая должна позволять пользователям помещаться в группы. Эти группы могут свободно создаваться, редактироваться и удаляться другими привилегированными пользователями в системе. Эта часть проста; просто создайте таблицу group_users
, которая связывает пользователей с группами. (Если вы являетесь приверженцем нормализации, вы можете создать таблицу group
, которая просто списывает группы, а затем имеет таблицу group_users
, которая связывает их вместе), это тоже хорошо)
Здесь, где это становится сложно. Клиент хочет, чтобы группы также содержали группы, произвольную глубину и произвольное перекрытие (группы могут быть в нескольких группах, а группы могут содержать несколько групп). Это достаточно легко хранить (с таблицей group_groups
), но трудно запросить без какого-либо расширения, например, Oracle CONNECT BY.
Эта рекурсивная иерархия также должна быть ретроактивной - это означает, что если группа А содержит группу В, а группа В изменена, то группа А также будет изменена - поэтому я не могу обмануть и просто сгладить структуру. Если вы не верите мне, что его нельзя просто сгладить, рассмотрите эту ситуацию. У вас есть группа под названием "классные люди", которая содержит пользователей 1 и 2. Кто-то создает группу под названием "ДЕЙСТВИТЕЛЬНО классные люди", которая содержит пользователя 3 и содержит группу "классные люди". Когда я запрашиваю "ДЕЙСТВИТЕЛЬНО классных людей", я должен сделать вывод, что пользователи 1, 2 и 3 находятся в группе. Теперь скажите, что кто-то решает, что пользователь 2 больше не крутой человек и удаляет пользователя 2 из "крутых людей". После этого момента "ДЕЙСТВИТЕЛЬНО здоровые люди" содержат только пользователей 1 и 3. Если бы я изначально выровнял структуру, я бы не знал, чтобы удалить пользователя 2 из "ДЕЙСТВИТЕЛЬНО здоровых людей", когда я удалил его из "классных людей" ".
Таким образом, тривиальное выравнивание не будет работать в этом сценарии. Другие варианты, которые я рассмотрел:
- Выполнение рекурсии в коде.
- Слишком медленно для сложных групп, а также требует, чтобы вы выполняли связанные объединения в памяти, а не в базе данных
- Сгладьте структуру в
group_users_flattened
, но также сохраните таблицуgroup_groups
. Создайте триггер дляgroup_users_flattened
в INSERT/UPDATE/DELETE, который перейдет в таблицуgroup_groups
, найдите все группы, которые содержат эту группу, и динамически внесите соответствующие изменения вgroup_users_flattened
.- Я могу представить, что это работает, но кажется запутанным и подверженным ошибкам, и у меня есть ощущение, что у меня есть то, что я не вижу.
Есть ли другие идеи, которые я не рассматривал?