Решение для предварительного просмотра пользовательских изменений и разрешения отката / фиксации в течение определенного периода времени - PullRequest
1 голос
/ 18 января 2011

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

У нас естьсложная структура данных, в которой все различные объекты тесно взаимосвязаны, причем почти все объекты сильно зависят / зависят от объектов других типов.

Проект представляет собой веб-сайт (MVC3, .NET 4), и вселогика реализована с использованием LINQ-to-SQL (2008) на бизнес-уровне.

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

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

  1. Удержание открытой транзакции в течение периода времени, который требуется пользователю для внесения нескольких измененийвоняет, так что все вышло.
  2. Хранение копии всех данных в памяти (или кэшированных на диск) - вариант, но его много, поэтому он кажется необоснованным.
  3. Сохранение набора вторичных таблиц или попытка использовать состояние сеанса для сохранения изменений, но это сложно и сложно поддерживать.
  4. Использование двух баз данных, переключение между ними по строке соединения ииспользуя T-SQL для управления репликацией, синхронизируя их после фиксации / отката.Т.е. включение / выключение, принудительное создание снимка, изменение направления и т. Д.

Мы немного озадачены решением, относительно простым в обслуживании.Есть предложения?

Ответы [ 4 ]

1 голос
/ 18 января 2011

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

На стороне клиента мы реализуем IEditableObject в классах модели пользовательского интерфейса. Наши классы моделей содержат ссылку на экземпляр объекта службы, который был получен при вызове службы. Это позволяет пользовательскому интерфейсу выполнять редактирование «Начало / Конец / Отмена» и выполнять фиксацию или откат при необходимости. Удерживая экземпляр исходного объекта службы, мы можем видеть исходные и текущие данные, которые позволят пользователю получить «предварительный просмотр», который вы ищете.

Хотя наше решение не реализует LINQ, я не верю, что в нашем подходе есть что-то уникальное, что также помешало бы вам использовать LINQ.

НТН

0 голосов
/ 18 января 2011

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

Во-первых, есть какая-то система блокировки, как описано в @ user580122, чтобы пометить / записать факт выполнения одной из этих транзакций. (Не забудьте включить какую-то периодическую автоматическую проверку, чтобы проверить потерянные или отмененные транзакции!)

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

Далее выясним, как использовать снимки базы данных. Читайте об этом в BOL; общая идея заключается в том, что вы создаете моментальный снимок базы данных, делаете с ним все, что хотите, и в конечном итоге выбрасываете его. (Доступно только в SQL 2005 и более поздних версиях, только в выпуске Enterprise.)

Итак:

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

Да, это конечно пахнет, и это может не относиться к вашей проблеме. Надеюсь, что идеи помогут вам что-то придумать.

0 голосов
/ 18 января 2011

Используйте набор дополнительных таблиц.

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

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

Вы можете оформить запрос следующим образом:

SELECT  *
FROM    mytable
AS OF TIMESTAMP
        TO_TIMESTAMP('2010-01-17')

в Oracle, но не в SQL Server.

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

0 голосов
/ 18 января 2011

Учитывайте следующее:

  1. Длинные транзакции делают систему менее масштабируемой.Если вы выполняете команду UPDATE, обновление блокируется до фиксации / отката, что препятствует выполнению другой транзакции.
  2. Вторые таблицы / база данных могут быть изменены параллельными транзакциями, поэтому вы не можете полагаться на данные в таблицах.Единственный способ - заблокировать его => см. № 1.
  3. Сериализуемая транзакция в некоторых механизмах данных использует версии данных в ваших таблицах.Таким образом, после выполнения первого cmd транзакция может видеть точные данные, доступные во время выполнения cmd.Это может помочь вам показать изменения, сделанные пользователем, но вы не можете гарантировать их сохранение в хранилище.
  4. DataSets содержит старую / новую версию данных.Но это, к сожалению, выходит за рамки вашей технологической цели.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...