как правильно завершить транзакцию

Автор Тема: как правильно завершить транзакцию  (Прочитано 4117 раз)

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

Оффлайн simson43Автор темы

  • ADN OPEN
  • ****
  • Сообщений: 411
  • Карма: 9
Добрый вечер назрел еще вопрос.
Если я работаю внутри транзакции и хочу вернуть что то из метода или вовсе выйти из него (return) или же goto метка. мне необходимо вначале закрыть транзакцию?

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Транзакцию следует создавать в using. если вы выйдите из метода где создали транзакцию без вызова commit, то перед автоматическим диспозом будет вызван откат всех изменений.

Оффлайн simson43Автор темы

  • ADN OPEN
  • ****
  • Сообщений: 411
  • Карма: 9
да я использую using
я вот тоже вычитал если выход из транзакции до commit то вызывается dispose и/или вроде бы abort
т е все что сделано внутри транзакции будто и не делалось верно?
иначе же следует в этом ответвлении также прописать commit?

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Не вроде бы, а 100% abort.
Все изменения отменяются, как будто и не было.
Да, пишите tr.Commit() перед return.

Оффлайн simson43Автор темы

  • ADN OPEN
  • ****
  • Сообщений: 411
  • Карма: 9
понял спасибо!

Оффлайн Вильдар

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
А, как вам такой метод расширения:
Код - C# [Выбрать]
  1. public static void StartTransaction(this Document doc, Action<Transaction> action)
  2. {
  3.      using (doc.LockDocument())
  4.      using (var t = doc.TransactionManager.StartTransaction())
  5.      {
  6.           action(t);
  7.           t.Commit();
  8.      }
  9. }
И можно забыть про вызов Commit()  8)
Использование:
Код - C# [Выбрать]
  1. doc.StartTransaction(t =>
  2. {
  3.        // свой код...
  4. });

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
А, как вам такой метод расширения:
Вильдар, изящно! Я бы, правда, по-другому бы сделал - не люблю объёмные лямбда-выражения:
Код - C# [Выбрать]
  1. public class TransactionHelper : IDisposable
  2. {
  3.     readonly Transaction _tr;
  4.     readonly DocumentLock _docLoc;
  5.  
  6.     public TransactionHelper(Document doc, out Transaction tr, bool lockDoc = true)
  7.     {
  8.         if (lockDoc) _docLoc = doc.LockDocument();
  9.         _tr = doc.TransactionManager.StartTransaction();
  10.         tr = _tr;
  11.     }
  12.  
  13.     public TransactionHelper(Database db, out Transaction tr)
  14.     {
  15.         _tr = db.TransactionManager.StartTransaction();
  16.         tr = _tr;
  17.     }
  18.  
  19.     public void Dispose()
  20.     {
  21.         _tr?.Commit();
  22.         _tr?.Dispose();
  23.         _docLoc?.Dispose();
  24.     }
  25. }
  26.  
Использование:
Код - C# [Выбрать]
  1. using (new TransactionHelper(adoc, out Transaction tr, false))
  2. {
  3.     BlockTableRecord cSpace = tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord;
  4. }
  5.  
  6. using (new TransactionHelper(db, out Transaction tr))
  7. {
  8.     BlockTableRecord cSpace = tr.GetObject(db.CurrentSpaceId, OpenMode.ForRead) as BlockTableRecord;
  9. }
  10.  

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Жесть. Такой изврат ради того, чтоб не писать tr.Commit () ?! Вы серьезно считаете что это проще?  Или я живу в другой вселенной....

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Жесть. Такой изврат ради того, чтоб не писать tr.Commit () ?! Вы серьезно считаете что это проще?  Или я живу в другой вселенной....
Ты не прав. Когда нужно чтобы в любом случае выполнился Commit с учетом всех возможных исключений - это идеальный вариант.
IMHO идея Autodesk'овцев что при Transaction.Dispose() выполняется откат транзакции если не выполнен Transaction.Commit мне кажется в корне неправильным.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Вильдар

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
Дмитрий Загорулькин, да, тоже такое сделал сначала. Но, потом убрал, т.к. при исключениях все равно будет вызван Commit(), мне кажется это не хорошо.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: как правильно завершить транзакцию
« Ответ #10 : 14-10-2018, 18:02:15 »
Жесть. Такой изврат ради того, чтоб не писать tr.Commit () ?! Вы серьезно считаете что это проще?  Или я живу в другой вселенной....
Ну да. Голова не болит - поставил я Commit или нет? Иногда, например, если полученный объект не соответствует критериям, то ставишь return и выходишь из метода задолго до конца блока using транзакции. В этом случае надо тоже не забыть перед return Commit сделать. А таких мест может быть несколько, нужно держать в голове всё время эту особенность с Commit, концентрироваться на этом. А вот такие вот "извраты" позволяют меньше уделять внимания этим мелочам и больше концентрироваться на непосредственно реализации задачи. Можно сказать, что эти "извраты" - это обёртки, позволяющий сгладить некоторые огрехи AutoCAD API. Со временем, таких обёрток довольно много набирается. Методы со встроенными проверками. Методы, которые учитывают различные особенности, с которыми столкнулся в прошлом. Методы, которые просто упрощают взаимодействие с API. И т.п. Посади меня сейчас писать приложение "с нуля" без использования моих вспомогательных библиотек - я буду себя чувствовать крайне неуютно.
Но, потом убрал, т.к. при исключениях все равно будет вызван Commit(), мне кажется это не хорошо.
Возможно. Как-то даже не задумывался об этом. А при исключении не всё равно что в итоге будет: Commit или Abort? У меня обычно с высокой вероятностью далее будет Fatal Error  :)

Оффлайн Вильдар

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
Re: как правильно завершить транзакцию
« Ответ #11 : 14-10-2018, 18:51:14 »
Про фатал метко подмечено  :'(
Если до исключения, будут созданы какие-то объекты, но до логического конца команда не дошла. То, правильнее, наверно, откатить все изменения.
А "умная" транзакция, пропустив исключение дальше, вызовит Commit().

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Re: как правильно завершить транзакцию
« Ответ #12 : 14-10-2018, 21:07:48 »
Что часто приходится выходить из процедуры до финального коммита - это однозначно так. А вот подменять дефолтное поведение на любое свое - это отличный способ подложить себе грабли на будущее. ИМХО наилучший вариант - явно написать, что делать транзакции в данном случае - аборт или коммит. в случае исключения - конечно аборт. и правильно его сделали дефолтным. одними граблями меньше. не завидую тем,  кому придется дописывать что-то на базе вашего кода с такими "улучшайзерами". это как перегрузить == на !=
А про то, что кучи своих вспомагательных классов и взяких хелперов здорово ускоряют работу - тут я конечно ЗА. спорить не о чем

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: как правильно завершить транзакцию
« Ответ #13 : 14-10-2018, 21:47:20 »
А вот подменять дефолтное поведение на любое свое - это отличный способ подложить себе грабли на будущее.
А где тут подмена? В варианте от Вильдара всё работает точно так же, как если бы не использовался вспомогательный метод. В моём, с учётом замечания Вильдара, возможно что нет. Если это критично - значит пользуемся его вариантом.
не завидую тем,  кому придется дописывать что-то на базе вашего кода с такими "улучшайзерами"
А в чём проблема? Заглянуть в определение метода расширения и понять как он работает - дело пары минут. Думаю, что наоборот даже - можно позавидовать. Человек увидит, как можно легко упростить себе жизнь использованием таких обёрток и возьмёт себе на вооружение.
это как перегрузить == на !=
По мне - это совсем неподходящее сравнение. В данном случае логика работы никак не подменяется на противоположную, просто объединяются несколько операций в одну.