Что вы хотите решить, так это синхронизировать две модели: у вас есть модель в памяти и модель базы данных. Простое распространение каждого изменения в базе данных, как это бывает, слишком дорого. Кроме того, вы хотите иметь возможность обрабатывать ошибки (то есть возвращать вашу модель в согласованное состояние). Чтобы быть в состоянии сделать это, у вас должен быть способ сказать «сейчас, это непротиворечиво».
Текущее решение состоит в том, чтобы запустить транзакцию в базе данных, когда известно, что модель является согласованной (обычно до того, как вы начнете вносить изменения), а затем выполнить все изменения в режиме в памяти, сопоставить их каким-либо образом с базой данных обновите базу данных и подтвердите транзакцию.
Хотя это звучит просто, программирование ОО активно мешает. Мы скрываем операции с моделями глубоко в структуре вызовов, мы очень стараемся, чтобы пользователи фрагмента кода не знали, что на самом деле делает этот код. В идеальном мире ваши инструменты разработки должны развернуть весь код, необходимый операции, в один метод / функцию, обернуть его в транзакцию и покончить с этим.
Это не работает. Вместо этого мы решили ввести глобальную переменную: сессию. Что плохо, и нам стыдно за это, поэтому мы пытаемся скрыть этот факт, но сессия является глобальной - для каждой операции. Теперь вам нужен способ прикрепить сеанс к операции. Вы можете сказать «весь код, который выполняется в текущем потоке, является одной операцией». Если вы это сделаете, естественным решением будет сделать сеанс глобальным для потока.
Или у вас есть какой-то жетон. Затем вы прикрепите сеанс к токену и передадите его.
Но фундаментальная проблема была и всегда заключалась в следующем: как прикрепить сеанс к одной операции на модели. Твердые детали должны знать, когда начинается операция, когда она заканчивается и как обрабатывать ошибки.
Для веб-приложений использование запроса является естественным способом определения операции: все, что происходит во время запроса, рассматривается как один шаг. Приложение на самом деле не хранит модель в памяти; все забывается в конце запроса и снова загружается из базы данных при поступлении следующего запроса. Медленно, но управляемо.
Настольные приложения - это совершенно другой зверь. Они обычно сохраняют всю модель в памяти все время. Мы не сохраняем изменения, пока пользователь не попросит об этом (когда она «сохраняет» свою работу), потому что это будет слишком медленно и, поскольку нет ничего похожего на запрос, не существует простого, автоматического способа определения «операции» .
Идея присоединить операцию к событию хороша. Только в настольных приложениях вы можете иметь несколько потоков, которые взаимодействуют с событиями, и теперь вам нужен способ пометить все события как «они принадлежат операции, начатой с события X, полученного давно». События обычно представляют собой небольшие неизменяемые фрагменты данных, поэтому вы не можете прикрепить к ним сеанс. Но вам нужен какой-то токен, чтобы пометить все события, которые принадлежат друг другу. Именно поэтому большинство настольных приложений либо работают с сервером (который снова работает как веб-приложение) и не имеют большой модели в памяти, либо не используют базу данных, а сохраняют свою модель в пользовательском формате (например, Office).