Правильный откат изменений в рамках транзакции. Как?

Автор Тема: Правильный откат изменений в рамках транзакции. Как?  (Прочитано 11765 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2465
  • Карма: 694
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Здравствуйте!
Имеется метод, в процессе выполнения которого создаются временные объекты, которые затем экспортируются в новый чертеж. Схематично это выглядит так:
Запуск транзакции
      Создание новых примитивов
            Добавление примитивов в пространство модели и в транзакцию           
       Копирование примитивов в новый чертеж
Завершение транзакции
Мне нужно, чтобы по завершении метода чертеж вернулся в исходное состояние.
1. Правильно я понимаю, что если транзакцию не подтвердить, то это произойдет автоматически?
2. Достаточно ли просто не добавлять Transaction.Commit() или нужно обязательно вызывать Transaction.Abort()?
3. Нужно ли уничтожать каким-либо образом созданные в транзакции объекты дополнительно?

Спасибо.

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2465
  • Карма: 694
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Сделал перед завершением транзакции Transaction.Abort(). Дополнительно никакого уничтожения создаваемых объектов не выполнял. Вроде работает как надо, пока никаких проблем не обнаружил.

Оффлайн Алексей Кулик

  • Administrator
  • *****
  • Сообщений: 948
  • Карма: 155
Прошу прощения, Александр Ривилис сейчас в отпуске, вернется не раньше понедельника. Думаю, он Вам подскажет ответы на вопросы. Я, к сожалению, не обладаю достаточной квалификацией для этого :(
Все, что сказано - личное мнение.

Правила форума существуют не просто так!

Приводя в сообщении код, не забывайте про его форматирование!

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2465
  • Карма: 694
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Ан нет, портится чертеж :(. То есть, такой подход не гарантирует откат всего, что внутри транзакции произошло.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13077
  • Карма: 1687
  • Рыцарь ObjectARX
  • Skype: rivilis
То есть, такой подход не гарантирует откат всего, что внутри транзакции произошло.
Откатывается только то, что управляется транзакцией.
P.S.: Честно говоря я не понял полную задачу. Например, зачем нужно добавлять примитивы в текущий чертеж?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2465
  • Карма: 694
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Примитивы получаются из расчленения имеющихся в чертеже (методом Explode). То есть, это некоторый аналог стандартной функции экспорта чертежа, выполненного в вертикальном приложении в обычный AutoCAD с дополнительными необходимыми мне опциями.
Я нашел причину, из-за которой портился чертеж. Я воспользовался методом по вставке определений блоков из библиотеки, разработанным Бушманом Андреем: https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/blockdefinitionsimport и указал последний параметр DuplicateRecordCloning.Replace. Во вставляемом блоке есть атрибут с текстовым стилем, имеющимся в чертеже. После того, как программа отрабатывала и чертеж сохранялся, из базы данных удалялся этот текстовый стиль. Изменив параметр на DuplicateRecordCloning.Ignore, я избавился от этой ошибки.
А что значит "управляется транзакцией"? Это те объекты, о существовании которых мы сообщаем методом AddNewlyCreatedDBObject?
Или все те объекты, которые создаются/модифицируются с момента запуска до завершения транзакции?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13077
  • Карма: 1687
  • Рыцарь ObjectARX
  • Skype: rivilis
А что значит "управляется транзакцией"? Это те объекты, о существовании которых мы сообщаем методом AddNewlyCreatedDBObject?
Или все те объекты, которые создаются/модифицируются с момента запуска до завершения транзакции?
Это те объекты, о которых транзакция знает, т.е.:
а) новые объекты, о которых мы сообщаем в методе AddNewlyCreatedDBObject
б) старые объекты, которые мы открываем методом GetObject транзакции или эквивалентными методами (например ObjectId.GetObject)
В общем чтобы получить список всех объектов, о которых "знает" транзакция, достаточно вызвать её метод GetAllObjects.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2465
  • Карма: 694
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Спасибо, это очень полезная информация!
В общем, получается так:
  • все объекты, добавленные в транзакцию методом AddNewlyCreatedDBObject удаляются, если отменить транзакцию (здесь и далее подразумевается использование метода Abort)
  • все объекты, открытые с помощью GetObject транзакции или эквивалентными методами (например ObjectId.GetObject) и модифицированные, если отменить транзакцию, возвращаются в исходное состояние
  • метод WblockCloneObjects с параметром DuplicateRecordCloning.Replace не только вставляет/заменяет имеющееся описание блока, но и вставляет/заменяет в чертеже используемый блоком текстовый стиль (а возможно и другую связанную с описанием блока информацию)
  • если отменить транзакцию, в рамках которой выполняется этот метод, то удаляется и вставка описания блока, и вставленный текстовый стиль, даже если он присутствовал ранее в чертеже и использовался другими объектами.
Появился в связи с этим еще один вопрос: а знает ли внешняя транзакция об объектах, о которых знает внутренняя транзакция?

Оффлайн fattyhallex

  • ADN Club
  • Сообщений: 16
  • Карма: 0
Или все те объекты, которые создаются/модифицируются с момента запуска до завершения транзакции?
Еще надо иметь в виду объекты которые удаляются, можно подумать об методе
Database.ReclaimMemoryObjectIds(idsCollection), также диспозить объекты
не резиденты для данной Database

Оффлайн fattyhallex

  • ADN Club
  • Сообщений: 16
  • Карма: 0
а знает ли внешняя транзакция об объектах, о которых знает внутренняя транзакция?
Это TopTransaction она в курсе всех изменений :)

Отмечено как Решение Дмитрий Загорулькин 08-10-2014, 14:58:00

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13077
  • Карма: 1687
  • Рыцарь ObjectARX
  • Skype: rivilis
Появился в связи с этим еще один вопрос: а знает ли внешняя транзакция об объектах, о которых знает внутренняя транзакция?
Не обязана знать. Но если интересно, то можешь поэкспериментировать.
метод WblockCloneObjects с параметром DuplicateRecordCloning.Replace не только вставляет/заменяет имеющееся описание блока, но и вставляет/заменяет в чертеже используемый блоком текстовый стиль (а возможно и другую связанную с описанием блока информацию)
Дело в том, что метод WblockCloneObjects не использует механизм транзакции, и соотвественно транзакции не известны все объекты, которые будут модифицированы при вызове WblockCloneObjects.
P.S.: Мне не нравится вообще использование Transaction.Abort, которая часто во много раз медленнее чем Transaction.Commit. Я бы задумался над изменением алгоритма.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн fattyhallex

  • ADN Club
  • Сообщений: 16
  • Карма: 0
Мне не нравится вообще использование Transaction.Abort, которая часто во много раз медленнее чем Transaction.Commit. Я бы задумался над изменением алгоритма.
Согласен, никогда не использую метод Abort, лучше заключать в объекты в блок using {...}
P.S.:Чтобы не сохранять изменения в базе данных можно еще посмотреть флаги

Оффлайн Дмитрий ЗагорулькинАвтор темы

  • ADN
  • *
  • Сообщений: 2465
  • Карма: 694
  • LISP/C#, AutoCAD/Civil 3D
  • Skype: zagor_dmtr
Еще надо иметь в виду объекты которые удаляются, можно подумать об методе
Database.ReclaimMemoryObjectIds(idsCollection), также диспозить объекты
не резиденты для данной Database
Объекты я не удаляю, так что мне пока без надобности. Но на будущее учту, спасибо!
Это TopTransaction она в курсе всех изменений
Не обязана знать. Но если интересно, то можешь поэкспериментировать.
Несколько противоречиво :) Ладно, буду испытывать.
P.S.: Мне не нравится вообще использование Transaction.Abort, которая часто во много раз медленнее чем Transaction.Commit. Я бы задумался над изменением алгоритма.
Есть такое, на откат изменений довольно много времени уходит, но это несколько секунд. Предыдущий вариант моей программы был на VisualLISP, и гораздо больше времени занимал. Там, правда, алгоритм совершенно другой.
Согласен, никогда не использую метод Abort
Было очень заманчиво - так просто выполнить откат, без дополнительных телодвижений :) А так, придется запоминать первоначальное состояние изменяемых объектов, а потом его восстанавливать. То есть, кода побольше получится, в варианте с отменой транзакции: просто изменить, в варианте без отмены: запомнить - изменить - восстановить. И при добавлении функционала нужно будет помнить, что изменения в 3 места надо вносить, вместо 1.
P.S.:Чтобы не сохранять изменения в базе данных можно еще посмотреть флаги
Где смотреть? Какие флаги? :)
P.S. Имеется в виду второй параметр метода AddNewlyCreatedDBObject?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13077
  • Карма: 1687
  • Рыцарь ObjectARX
  • Skype: rivilis
А так, придется запоминать первоначальное состояние изменяемых объектов, а потом его восстанавливать. То есть, кода побольше получится, в варианте с отменой транзакции: просто изменить, в варианте без отмены: запомнить - изменить - восстановить. И при добавлении функционала нужно будет помнить, что изменения в 3 места надо вносить, вместо 1.
Мне кажется, что при озвученной постановке задачи можно не трогать текущий чертеж, а все действия производить с новым чертежом. Соотвественно ничего "откатывать" в текущем чертеже не придётся.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн fattyhallex

  • ADN Club
  • Сообщений: 16
  • Карма: 0