Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Дмитрий Загорулькин от 22-07-2013, 21:41:58

Название: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Дмитрий Загорулькин от 22-07-2013, 21:41:58
Здравствуйте!
Имеется метод, в процессе выполнения которого создаются временные объекты, которые затем экспортируются в новый чертеж. Схематично это выглядит так:
Запуск транзакции
      Создание новых примитивов
            Добавление примитивов в пространство модели и в транзакцию           
       Копирование примитивов в новый чертеж
Завершение транзакции
Мне нужно, чтобы по завершении метода чертеж вернулся в исходное состояние.
1. Правильно я понимаю, что если транзакцию не подтвердить, то это произойдет автоматически?
2. Достаточно ли просто не добавлять Transaction.Commit() или нужно обязательно вызывать Transaction.Abort()?
3. Нужно ли уничтожать каким-либо образом созданные в транзакции объекты дополнительно?

Спасибо.
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Дмитрий Загорулькин от 24-07-2013, 12:06:25
Сделал перед завершением транзакции Transaction.Abort(). Дополнительно никакого уничтожения создаваемых объектов не выполнял. Вроде работает как надо, пока никаких проблем не обнаружил.
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Алексей Кулик от 25-07-2013, 11:36:08
Прошу прощения, Александр Ривилис сейчас в отпуске, вернется не раньше понедельника. Думаю, он Вам подскажет ответы на вопросы. Я, к сожалению, не обладаю достаточной квалификацией для этого :(
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Дмитрий Загорулькин от 26-07-2013, 13:16:56
Ан нет, портится чертеж :(. То есть, такой подход не гарантирует откат всего, что внутри транзакции произошло.
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Александр Ривилис от 28-07-2013, 03:16:12
То есть, такой подход не гарантирует откат всего, что внутри транзакции произошло.
Откатывается только то, что управляется транзакцией.
P.S.: Честно говоря я не понял полную задачу. Например, зачем нужно добавлять примитивы в текущий чертеж?
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Дмитрий Загорулькин от 28-07-2013, 23:35:48
Примитивы получаются из расчленения имеющихся в чертеже (методом Explode). То есть, это некоторый аналог стандартной функции экспорта чертежа, выполненного в вертикальном приложении в обычный AutoCAD с дополнительными необходимыми мне опциями.
Я нашел причину, из-за которой портился чертеж. Я воспользовался методом по вставке определений блоков из библиотеки, разработанным Бушманом Андреем: https://sites.google.com/site/bushmansnetlaboratory/sendbox/stati/blockdefinitionsimport и указал последний параметр DuplicateRecordCloning.Replace. Во вставляемом блоке есть атрибут с текстовым стилем, имеющимся в чертеже. После того, как программа отрабатывала и чертеж сохранялся, из базы данных удалялся этот текстовый стиль. Изменив параметр на DuplicateRecordCloning.Ignore, я избавился от этой ошибки.
А что значит "управляется транзакцией"? Это те объекты, о существовании которых мы сообщаем методом AddNewlyCreatedDBObject?
Или все те объекты, которые создаются/модифицируются с момента запуска до завершения транзакции?
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Александр Ривилис от 28-07-2013, 23:52:56
А что значит "управляется транзакцией"? Это те объекты, о существовании которых мы сообщаем методом AddNewlyCreatedDBObject?
Или все те объекты, которые создаются/модифицируются с момента запуска до завершения транзакции?
Это те объекты, о которых транзакция знает, т.е.:
а) новые объекты, о которых мы сообщаем в методе AddNewlyCreatedDBObject
б) старые объекты, которые мы открываем методом GetObject транзакции или эквивалентными методами (например ObjectId.GetObject)
В общем чтобы получить список всех объектов, о которых "знает" транзакция, достаточно вызвать её метод GetAllObjects.
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Дмитрий Загорулькин от 29-07-2013, 01:42:00
Спасибо, это очень полезная информация!
В общем, получается так:
Появился в связи с этим еще один вопрос: а знает ли внешняя транзакция об объектах, о которых знает внутренняя транзакция?
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: fattyhallex от 29-07-2013, 01:48:52
Или все те объекты, которые создаются/модифицируются с момента запуска до завершения транзакции?
Еще надо иметь в виду объекты которые удаляются, можно подумать об методе
Database.ReclaimMemoryObjectIds(idsCollection), также диспозить объекты
не резиденты для данной Database
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: fattyhallex от 29-07-2013, 01:50:39
а знает ли внешняя транзакция об объектах, о которых знает внутренняя транзакция?
Это TopTransaction она в курсе всех изменений :)
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Александр Ривилис от 29-07-2013, 01:57:43
Появился в связи с этим еще один вопрос: а знает ли внешняя транзакция об объектах, о которых знает внутренняя транзакция?
Не обязана знать. Но если интересно, то можешь поэкспериментировать.
метод WblockCloneObjects с параметром DuplicateRecordCloning.Replace не только вставляет/заменяет имеющееся описание блока, но и вставляет/заменяет в чертеже используемый блоком текстовый стиль (а возможно и другую связанную с описанием блока информацию)
Дело в том, что метод WblockCloneObjects не использует механизм транзакции, и соотвественно транзакции не известны все объекты, которые будут модифицированы при вызове WblockCloneObjects.
P.S.: Мне не нравится вообще использование Transaction.Abort, которая часто во много раз медленнее чем Transaction.Commit. Я бы задумался над изменением алгоритма.
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: fattyhallex от 29-07-2013, 09:47:26
Мне не нравится вообще использование Transaction.Abort, которая часто во много раз медленнее чем Transaction.Commit. Я бы задумался над изменением алгоритма.
Согласен, никогда не использую метод Abort, лучше заключать в объекты в блок using {...}
P.S.:Чтобы не сохранять изменения в базе данных можно еще посмотреть флаги
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Дмитрий Загорулькин от 29-07-2013, 10:47:08
Еще надо иметь в виду объекты которые удаляются, можно подумать об методе
Database.ReclaimMemoryObjectIds(idsCollection), также диспозить объекты
не резиденты для данной Database
Объекты я не удаляю, так что мне пока без надобности. Но на будущее учту, спасибо!
Это TopTransaction она в курсе всех изменений
Не обязана знать. Но если интересно, то можешь поэкспериментировать.
Несколько противоречиво :) Ладно, буду испытывать.
P.S.: Мне не нравится вообще использование Transaction.Abort, которая часто во много раз медленнее чем Transaction.Commit. Я бы задумался над изменением алгоритма.
Есть такое, на откат изменений довольно много времени уходит, но это несколько секунд. Предыдущий вариант моей программы был на VisualLISP, и гораздо больше времени занимал. Там, правда, алгоритм совершенно другой.
Согласен, никогда не использую метод Abort
Было очень заманчиво - так просто выполнить откат, без дополнительных телодвижений :) А так, придется запоминать первоначальное состояние изменяемых объектов, а потом его восстанавливать. То есть, кода побольше получится, в варианте с отменой транзакции: просто изменить, в варианте без отмены: запомнить - изменить - восстановить. И при добавлении функционала нужно будет помнить, что изменения в 3 места надо вносить, вместо 1.
P.S.:Чтобы не сохранять изменения в базе данных можно еще посмотреть флаги
Где смотреть? Какие флаги? :)
P.S. Имеется в виду второй параметр метода AddNewlyCreatedDBObject?
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Александр Ривилис от 29-07-2013, 18:21:16
А так, придется запоминать первоначальное состояние изменяемых объектов, а потом его восстанавливать. То есть, кода побольше получится, в варианте с отменой транзакции: просто изменить, в варианте без отмены: запомнить - изменить - восстановить. И при добавлении функционала нужно будет помнить, что изменения в 3 места надо вносить, вместо 1.
Мне кажется, что при озвученной постановке задачи можно не трогать текущий чертеж, а все действия производить с новым чертежом. Соотвественно ничего "откатывать" в текущем чертеже не придётся.
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: fattyhallex от 29-07-2013, 18:34:21
Какие флаги?
Я имел в виду CommandFlags, немного информации здесь:
http://spiderinnet1.typepad.com/.services/blog/6a0153928ee38e970b0153928f11cc970b/search?filter.q=CommandFlags
Название: Re: Правильный откат изменений в рамках транзакции. Как?
Отправлено: Дмитрий Загорулькин от 31-07-2013, 14:38:41
Мне кажется, что при озвученной постановке задачи можно не трогать текущий чертеж, а все действия производить с новым чертежом. Соотвественно ничего "откатывать" в текущем чертеже не придётся.
Тогда придется долго и нудно чистить целевой чертеж от ненужных объектов, потому что в вертикальных решениях есть неразрывная динамическая связь между объектами и при копировании нужных объектов будет цепляться куча ненужных. Причем, я даже до конца не знаю размеры этой кучи...
Я имел в виду CommandFlags
Флаги посмотрел, но отвечающего за сохранность чертежа не обнаружил. Возможно Вы имели в виду флаги блокировки документа, но они его блокируют от изменений другими командами, а не от выполняемой.
Спасибо за консультации! Как время появится, переделаю программу с целью избавления от метода Abort. Попробую вручную удалять создаваемые объекты перед завершением транзакции.