1

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

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

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

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

Мы рассмотрели эти варианты:

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

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

ответ

1

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

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

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

НТН

+0

Не соответствует его требованиям, но здесь есть много хороших идей. –

+0

Хорошо, но не совсем то, что нам нужно. Это по существу вариант 2 в моем списке, так как нам требуется блокировка (очень) большого набора данных. – enashnash

+0

Несмотря на мой комментарий выше, это решение, которое я использовал, поэтому я отметил его как ответ. Я не уверен, является ли этот ответ или тот, что у @Quassnoi самый _correct_, хотя он работает лучше всего в моем случае. – enashnash

0

Рассмотрим это:

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

Причина, по которой мы рассматривали вариант 1, заключается в том, что когда-нибудь будет только один пользователь, изменяющий данные, которые будут заблокированы. Но пахнет. Что касается 3 в вашем списке, я обновлю свой вопрос, чтобы уточнить, что я имею в виду. – enashnash

0

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

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

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

Вы можете оформить запрос, как это:

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

в Oracle, но не в SQL Server.

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

0

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

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

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

В следующем примере вы узнаете, как использовать моментальные снимки базы данных. Прочитайте их в BOL; общая идея заключается в том, что вы создаете мгновенный снимок базы данных, делаете все, что хотите с ней, и в конце концов выбросите ее.

So (Доступно только в SQL Server 2005 и выше, только Enterprise Edition.):

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

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

Смежные вопросы