Лучшие практики мягкого удаления (PHP / MySQL) - PullRequest
25 голосов
/ 16 февраля 2011

Проблема

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

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

Я думаю о внедрении софт-удаления.Итак, как обычно это делают?

Мои ближайшие мысли

Моя первая мысль - вставить столбец "flag_softdeleted TINYINT NOT NULL DEFAULT 0" в каждомтаблица объектов, которые должны быть мягко удаляемыми.Или, может быть, вместо этого использовать временную метку?

Затем я предоставляю кнопку «Показать удаленные» или «Восстановить» в каждом соответствующем графическом интерфейсе.Нажав на эту кнопку, вы включите удаленные записи в результат.Каждая удаленная запись имеет кнопку «Восстановить».Имеет ли это смысл?

Ваши мысли?

Кроме того, я буду признателен за любые ссылки на соответствующие ресурсы.

Ответы [ 6 ]

32 голосов
/ 16 февраля 2011

Вот как я это делаю. У меня есть поле is_deleted, которое по умолчанию равно 0. Тогда запросы просто проверяют WHERE is_deleted = 0.

Я стараюсь держаться подальше от любых жестких удалений, насколько это возможно. Иногда они необходимы, но я делаю это только для администратора. Таким образом, мы можем жестко удалить, но пользователи не могут ...

Редактировать: На самом деле, вы можете использовать это, чтобы иметь несколько «слоев» мягкого удаления в вашем приложении. Таким образом, каждый может быть кодом:

  • 0 -> Не удалено
  • 1 -> Soft Deleted, отображается в списках удаленных элементов для пользователей управления
  • 2 -> Soft Deleted, не отображается ни для одного пользователя, кроме пользователей с правами администратора
  • 3 -> Отображается только для разработчиков.

Наличие двух других уровней все еще позволит менеджерам и администраторам убирать удаленные списки, если они становятся слишком длинными. А поскольку код переднего конца просто проверяет наличие is_deleted = 0, он прозрачен для внешнего интерфейса ...

8 голосов
/ 16 февраля 2011

Использование программ мягкого удаления - обычная вещь для реализации, и они очень полезны для многих вещей, таких как:

  • Сохранение данных пользователя при удалении чего-либо
  • Сохранение ваших собственных данных при удалении чего-либо
  • Вести учет того, что действительно произошло (своего рода аудит)
  • 1010 * прочее *

Есть одна вещь, на которую я хочу обратить внимание, что почти все пропускают, и она всегда возвращается, чтобы укусить вас в заднюю часть. Пользователи вашего приложения не понимают delete так же, как вы.

Существуют различные градусы удалений. Типичный пользователь удаляет вещи, когда он

  • Сделал ошибку и хочу удалить плохие данные
  • Больше не хочет видеть что-либо на экране

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

Посмотрите на следующие данные:

PRICES | item | price | deleted |
       +------+-------+---------+
       |   A  |  101  |    1    |
       |   B  |  110  |    1    |
       |   C  |  120  |    0    |
       +------+-------+---------+

Некоторые пользователи не хотят показывать цену товара B, так как они больше не продают этот товар. Поэтому он удаляет это. Другой пользователь создал ошибку для элемента A по ошибке, поэтому он удалил ее и создал цену для элемента C, как и предполагалось. Теперь вы можете показать мне список цен на все продукты? Нет, потому что либо вы должны отобразить потенциально ошибочные данные (A), либо исключить все, кроме текущих цен (C).

Конечно, с вышеизложенным можно бороться любым количеством способов. Моя точка зрения такова, что ВЫ должны быть очень четкими с тем, что ВЫ подразумевает под удалением, и убедиться, что пользователи не могут неправильно их понять. Один из способов - заставить пользователя сделать выбор (скрыть / удалить).

5 голосов
/ 16 февраля 2011

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

1 голос
/ 16 февраля 2011

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

Я бы сделал архивирование, чтобы избежать серьезного обновления рабочего кода.Но если вы хотите использовать поле удаленного флага, используйте его как метку времени, чтобы дать вам дополнительную полезную информацию помимо логического.(Null = не удалено.) Вы также можете добавить поле DeletedBy, чтобы отслеживать пользователя, ответственного за удаление записи.Использование двух полей дает вам много информации о том, кто удалил что и когда.(Решение с двумя дополнительными полями также может быть сделано в архивной таблице / базе данных.)

1 голос
/ 16 февраля 2011

Я всегда только что использовал удаленный столбец, как вы упомянули. Там действительно не намного больше, чем это. Вместо удаления записи просто установите для поля удалено значение true.

Некоторые компоненты, которые я создаю, позволяют пользователю просматривать все удаленные записи и восстанавливать их, другие просто отображают все записи, где удалено = 0

0 голосов
/ 16 февраля 2011

Наиболее распространенный сценарий, с которым я столкнулся, это то, что вы описываете, tinyint или даже bit, представляющий статус IsActive или IsDeleted.В зависимости от того, считаются ли эти данные «деловыми» или «постоянными», они могут быть максимально прозрачно встроены в логику приложения / домена, например, непосредственно в хранимых процедурах и неизвестны коду приложения.Но, похоже, это законная бизнес-информация для ваших нужд, поэтому ее необходимо знать по всему коду.(Таким образом, пользователи могут просматривать удаленные записи, как вы предлагаете.)

Другой подход, который я видел, состоит в использовании комбинации двух временных меток для отображения «окна» активности для данной записи.Это немного больше кода для его поддержки, но преимущество в том, что можно запланировать мягкое удаление чего-либо в заранее определенное время.Например, продукты с ограниченным сроком действия могут быть установлены таким образом, когда они создаются.(Чтобы сделать запись активной на неопределенный срок, можно использовать максимальное значение (или просто какую-то нелепо отдаленную будущую дату) или просто указать конечную дату null, если вы согласны с этим).есть дальнейшее рассмотрение того, что время от времени удаляется / восстанавливается, и отслеживает какой-то аудит для этого.Подход с использованием флагов знает только текущее состояние, а подход с использованием временных отметок знает только самое последнее окно.Но что-либо настолько сложное, как контрольный журнал, должно определенно храниться отдельно от рассматриваемых записей.

...