Есть ли примеры не CRUD подходов?

14

Я программист, но также работал архивариусом. Как архивариус, очень важно хранить данные.

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

Есть ли термин для этого? В основном только создание и чтение данных? Есть ли примеры такого подхода?

Питер Б
источник
1
Is there a term for this? Basically only creating and reading data?Конечно, есть: CR; P
Яннис
7
С точки зрения пользователя, это все еще CRUD. Я не знаю каких-либо конкретных меток для этого стиля реализации, но я думаю, что это распространено в МНОГИХ приложениях. (Обмен стеками - хороший пример ...)
Марк Э. Хаас
Возможно, вы захотите посмотреть доклад под названием «Несоответствие импеданса - наша ошибка» .
Антон Барковский
+1 В какой-то момент кому-то понадобятся отчеты, и очень сложно создавать отчеты по несуществующим данным, поскольку они «обновлены» из-за отсутствия. Я считаю ваш подход очень дальновидным.
Чак Конвей
2
Вы также можете посмотреть выступление о Datomic: infoq.com/presentations/The-Design-of-Datomic
Марьян Венема,

Ответы:

16

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

Следует отметить, что это спорная техника. Смотрите ссылки: Con vs Pro .

прецизионный самописец
источник
11

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

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

Система не работает
источник
3
Эта. Кроме того, ссылочная целостность становится кошмаром; Вы не можете указать внешний ключ для «одной записи в этой таблице с этим неуникальным ключом, который не помечен как удаленный». Вы можете обойти это, сохранив данные для копии записи, которая должна быть обновлена, в другую таблицу, прежде чем обновлять эту «рабочую копию» новыми данными, но у вас все еще есть большой объем данных, с которым приходится иметь дело.
KeithS
5

EventSourcing звучит как шаблон, который вы, возможно, ищете.

Давайте рассмотрим пример, использующий простой объект «car», который мы хотели бы отслеживать цвета (псевдо-код C # следует).

public class Car {
  public string Color { get; set; }
  public Car() { this.Color = "Blue"; }
}

При реализации CRUD при обновлении цвета автомобиля предыдущий цвет будет потерян.

MyCar.Color = "Red";
MyCar.Save();  // Persist the update to the database and lose the previous data

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

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

public class Car {
    public string Color { get; private set; } // Cannot be set from outside the class

    public void ApplyEvent(CarColorChangedEvent e) {
      this.Color = e.Color;
    }
}

Теперь, как бы мы обновили цвет этого объекта? Мы могли бы создать событие CarColorChanged !

var evnt = new CarColorChangedEvent("Red");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Заметили отсутствие сохранения на реальном объекте модели? Это потому, что вместо того, чтобы сохранять модель напрямую, мы сохраняем события, которые переводят модель в текущее состояние. Эти события должны быть неизменными .

Теперь давайте перенесемся и изменим цвет еще несколько раз:

var evnt = new CarColorChangedEvent("Green");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

var evnt = new CarColorChangedEvent("Purple");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Если бы мы посмотрели на наше хранилище событий (это может быть база данных отношений, на основе файлов и т. Д.), Мы бы увидели серию событий, связанных с нашим автомобильным объектом:

CarColorChangedEvent => Red
CarColorChangedEvent => Green
CarColorChangedEvent => Purple

Если бы мы хотели восстановить этот автомобильный объект, мы могли бы сделать это, просто создав новый автомобильный объект и применив события из нашего хранилища событий к указанному объекту.

var MyCar = new Car();
var events = MyDatabase.SelectEventsForCar("CarIdentifierHere");
foreach(var e in events) {
  MyCar.ApplyEvent(e);
}
Console.WriteLine(MyCar.Color); // Purple

С потоком событий мы можем откатить состояние автомобиля до предыдущего периода времени просто путем создания нового объекта автомобиля и применять только те события, которые мы хотим:

var MyCar = new Car();
var event = MyDatabase.GetFirstEventForCar("CarIdentifierHere");
MyCar.ApplyEvent(e);
Console.WriteLine(MyCar.Color); // Red
Майк
источник
5

Событие Sourcing - путь, и вы должны взглянуть на то, что Грег Янг должен сказать об этом.

http://goodenoughsoftware.net/

Также посмотрите на эту презентацию в его базе данных (Event Store). Вы можете найти и другие видео.

http://oredev.org/2012/sessions/a-deep-look-into-the-event-store

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

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

С моделью источников событий это не так. Вы всегда можете воспроизвести именно то, что сделал пользователь. Это очень важное различие между CRUD и Event Sourcing. Архитектура Event Sourcing сохраняет события в хранилище событий, а не объекты данных или объекты модели домена. Событие может легко повлиять на несколько объектов. Просто подумайте о решении для корзины покупок, в котором вы превращаете каждый элемент в корзине в фактический заказ. Одно событие влияет на все объекты товара, а также на объекты корзины покупок, которые преобразуются в объект заказа.

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

С помощью Event Sourcing вы можете легко перематывать, просто воспроизводя события до определенного момента времени. Быстрые перемотки вперед могут быть реализованы с помощью снимков, но это все вопрос реализации.

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

В случае отладки, как часто вы просите пользователя рассказать вам, что он сделал ... почему бы просто не повторить то, что он сделал, а затем пройтись по коду! Довольно изящно, да.

Надеюсь это поможет.

Джей Пит
источник
2

Не совсем твой пример, но в старых финансовых системах у тебя было хранилище WORM . Если вам нужно было «обновить», вы написали новую запись, и вы всегда называли последнюю запись текущей, но никакие зафиксированные данные не могли быть перезаписаны.

Многие люди перенесли эту идею в более поздние системы. Я слышал, что вы описываете как таблицы WORM, но только в этих кругах.

Билл
источник
2

Да, это довольно распространено в корпоративных системах, в основном это два подхода:

  • «двухвременный», в котором каждая запись имеет действительный от и действительный до отметки времени («текущая» запись, имеющая действительную на сегодняшний день дату «навсегда» - ноль, «9999-12-31» или некоторое такое высокое значение). Записи никогда не удаляются, вместо этого дата «действителен» устанавливается на текущее время, и в случае обновления вставляется новая запись с действительным датой текущего времени и всегда действительной на сегодняшний день.
  • «таблица истории» - каждый раз, когда изменяется запись, копия старой записи помещается в таблицу истории / журнала с отметкой времени для события.

Существуют большие различия в степени детализации для обоих подходов. Например, если количество виджетов в позиции заказа изменилось, ведете ли вы историю для всего заказа или только для этого одного элемента?

Вообще говоря, «двухвременный» - это много дополнительной работы, и он того стоит, если у вас много вариантов использования, таких как «аудитор получает статус заказа по состоянию на 31 декабря».

Джеймс Андерсон
источник
1

Вы можете использовать «soft-deletes», как предложено pdr . Что касается обновлений, вы можете хранить историю записей, вроде моего ответа здесь: /dba/28195/save-history-editable-data-rdbms/28201#28201, где ОП хотел бы быть в состоянии отслеживать все версии определенных видов данных.

FrustratedWithFormsDesigner
источник
-2

в основном не может быть завершено без этих 4 вещей. Crud означает создание, чтение, обновление и удаление, поэтому, когда вы только пытаетесь читать данные, вы можете использовать для этого простой запрос, но все эти три вещи связаны с одной и другой и простыми понятиями базы данных.

Тайяб Вохра
источник