Лучшие практики мягкого удаления (PHP/MySQL)
проблема
В веб-приложении, посвященном продуктам и заказам, я хочу поддерживать информацию и отношения между бывшими сотрудниками (пользователями) и заказами, которые они обрабатывали. Я хочу поддерживать информацию и отношения между устаревшими продуктами и заказами, которые включают эти продукты.
Тем не менее, я хочу, чтобы сотрудники имели возможность очищать интерфейсы администрирования, такие как удаление бывших сотрудников, устаревшие продукты, устаревшие группы продуктов и т. Д.
Я думаю о реализации софт-удаления. Итак, как обычно это сделать?
Мои непосредственные мысли
Моя первая мысль - воткнутьflag_softdeleted
TINYINT NOT NULL DEFAULT 0"столбец в каждой таблице объектов, которые должны быть легко удалены. Или, возможно, использовать вместо этого временную метку?
Затем я предоставляю кнопку "Показать удаленные" или "Восстановить" в каждом соответствующем графическом интерфейсе. Нажав на эту кнопку, вы включите мягко удаленные записи в результат. Каждая удаленная запись имеет кнопку "Восстановить". Имеет ли это смысл?
Твои мысли?
Также я буду признателен за любые ссылки на соответствующие ресурсы.
7 ответов
Вот как я это делаю. у меня есть is_deleted
поле по умолчанию 0. Затем запросы просто проверить WHERE is_deleted = 0
,
Я стараюсь держаться подальше от каких-либо жестких удалений как можно больше. Иногда они необходимы, но я делаю это только для администратора. Таким образом, мы можем жестко удалить, но пользователи не могут...
Изменить: На самом деле, вы можете использовать это, чтобы иметь несколько "слоев" мягкого удаления в вашем приложении. Таким образом, каждый может быть кодом:
0
-> Не удалено1
-> Soft Deleted, отображается в списках удаленных элементов для пользователей управления2
-> Soft Deleted, не отображается ни для одного пользователя, кроме пользователей с правами администратора3
-> Появляется только для разработчиков.
Наличие двух других уровней все еще позволит менеджерам и администраторам убирать удаленные списки, если они становятся слишком длинными. А так как интерфейсный код просто проверяет is_deleted = 0
это прозрачно для интерфейса...
Использование программ мягкого удаления - обычная вещь для реализации, и они очень полезны для многих вещей, таких как:
- Сохранение задницы пользователя, когда он что-то удалил
- Сохранение собственной задницы при удалении чего-либо
- Вести учет того, что действительно произошло (своего рода аудит)
- и так далее
Есть одна вещь, на которую я хочу обратить внимание: почти все скучают, и она всегда возвращается, чтобы укусить вас за заднюю часть. Пользователи вашего приложения не имеют такого же понимания удаления, как вы.
Существуют разные степени удаления. Типичный пользователь удаляет материал, когда он
- Сделал ошибку и хочу удалить плохие данные
- Больше не хочет видеть что-то на экране
Проблема в том, что если вы не записали намерение удаления, ваше приложение не сможет различить ошибочные данные (которые никогда не должны были создаваться) и исторически правильные данные.
Посмотрите на следующие данные:
PRICES | item | price | deleted |
+------+-------+---------+
| A | 101 | 1 |
| B | 110 | 1 |
| C | 120 | 0 |
+------+-------+---------+
Некоторые пользователи не хотят показывать цену товара B, так как они больше не продают этот товар. Поэтому он удаляет это. Другой пользователь по ошибке ошибочно создал цену для элемента A, поэтому он удалил ее и создал цену для элемента C, как и предполагалось. Теперь вы можете показать мне список цен на все продукты? Нет, потому что либо вы должны отобразить потенциально ошибочные данные (A), либо вы должны исключить все, кроме текущих цен (C).
Конечно, с вышеизложенным можно бороться любым количеством способов. Я хочу сказать, что вам нужно четко понимать, что вы подразумеваете под удалением, и следить за тем, чтобы пользователи не могли его неправильно понять. Один из способов - заставить пользователя сделать выбор (скрыть / удалить).
Если бы у меня был код, попадающий в эту таблицу, я бы добавил столбец и изменил имя таблицы. Затем я бы создал представление с тем же именем, что и текущая таблица, которая выбирает только активные записи. Таким образом, ни один из существующих кодов не сломается, и вы можете получить столбец мягкого удаления. Если вы хотите увидеть удаленную запись, вы выбираете из базовой таблицы, в противном случае вы используете представление.
Я всегда просто использовал удаленный столбец, как вы упомянули. Там действительно не намного больше, чем это. Вместо удаления записи просто установите для удаленного поля значение true.
Некоторые компоненты, которые я создаю, позволяют пользователю просматривать все удаленные записи и восстанавливать их, другие просто отображают все записи, где удалено = 0
Ваша идея имеет смысл и часто используется в производстве, но для ее реализации вам потребуется обновить довольно много кода, чтобы учесть новое поле. Другим вариантом может быть архивация (перемещение) "мягко удаленных" записей в отдельную таблицу или базу данных. Это также часто делается и делает проблему скорее обслуживанием, чем (пере) программированием. (Вы можете заставить триггер таблицы реагировать на удаление, чтобы заархивировать удаленную запись.)
Я бы сделал архивирование, чтобы избежать серьезного обновления производственного кода. Но если вы хотите использовать поле удаленного флага, используйте его как метку времени, чтобы дать вам дополнительную полезную информацию помимо логического. (Null = не удалено.) Вы также можете добавить поле DeletedBy, чтобы отслеживать пользователя, ответственного за удаление записи. Использование двух полей дает вам много информации о том, кто что удалил и когда. (Решение с двумя дополнительными полями также может быть сделано в архивной таблице / базе данных.)
Наиболее распространенный сценарий, с которым я столкнулся, это то, что вы описываете, tinyint
или даже bit
представляющий статус IsActive
или же IsDeleted
, В зависимости от того, считаются ли эти данные "деловыми" или "постоянными", они могут быть максимально прозрачно встроены в логику приложения / домена, например, непосредственно в хранимых процедурах и неизвестны коду приложения. Но, похоже, это законная бизнес-информация для ваших нужд, поэтому ее необходимо знать по всему коду. (Таким образом, пользователи могут просматривать удаленные записи, как вы предлагаете.)
Другой подход, который я видел, состоит в том, чтобы использовать комбинацию двух временных меток, чтобы показать "окно" активности для данной записи. Это немного больше кода для его поддержки, но преимущество в том, что можно запланировать мягкое удаление чего-либо в заранее определенное время. Например, продукты с ограниченным сроком действия могут быть установлены таким образом, когда они создаются. (Чтобы сделать запись активной бесконечно, можно использовать максимальное значение (или просто какую-то нелепо отдаленную будущую дату) или просто указать конечную дату null
если ты в порядке с этим.)
Затем, конечно, есть дальнейшее рассмотрение того, что время от времени удаляется / восстанавливается, и отслеживает какой-то аудит для этого. Подход с использованием флагов знает только текущее состояние, а подход с использованием временных отметок знает только самое последнее окно. Но что-либо настолько сложное, как контрольный журнал, должно определенно храниться отдельно от рассматриваемых записей.
Вместо этого я бы использовал таблицу bin , в которую можно было бы переместить все записи, удаленные из других таблиц. Основная проблема с флагом удаления заключается в том, что со связанными таблицами вы обязательно столкнетесь с двойной ошибкой ключа при попытке вставить новую запись.
Таблица bin может иметь такую структуру:
id, table_name, data, date_time, user
Где
- id — первичный ключ с автоинкрементом
- table_name — имя таблицы, из которой была удалена запись
- data содержит запись в формате JSON с именем и значением всех полей
- date_time — дата и время удаления
- user — идентификатор пользователя (если это предусмотрено системой), выполнившего операцию
этот способ не только избавит вас от проверки флажка удаления при каждом запросе (представьте себе запросы с большим количеством объединений), но и позволит иметь в таблицах только действительно нужные данные, облегчая любые поиски и исправления с помощью клиентских программ SQL