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

ADN Club => AutoCAD .NET API => Тема начата: simson43 от 13-10-2018, 19:21:32

Название: как правильно завершить транзакцию
Отправлено: simson43 от 13-10-2018, 19:21:32
Добрый вечер назрел еще вопрос.
Если я работаю внутри транзакции и хочу вернуть что то из метода или вовсе выйти из него (return) или же goto метка. мне необходимо вначале закрыть транзакцию?
Название: Re: как правильно завершить транзакцию
Отправлено: avc от 13-10-2018, 19:24:50
Транзакцию следует создавать в using. если вы выйдите из метода где создали транзакцию без вызова commit, то перед автоматическим диспозом будет вызван откат всех изменений.
Название: Re: как правильно завершить транзакцию
Отправлено: simson43 от 13-10-2018, 19:27:28
да я использую using
я вот тоже вычитал если выход из транзакции до commit то вызывается dispose и/или вроде бы abort
т е все что сделано внутри транзакции будто и не делалось верно?
иначе же следует в этом ответвлении также прописать commit?
Название: Re: как правильно завершить транзакцию
Отправлено: avc от 13-10-2018, 19:29:42
Не вроде бы, а 100% abort.
Все изменения отменяются, как будто и не было.
Да, пишите tr.Commit() перед return.
Название: Re: как правильно завершить транзакцию
Отправлено: simson43 от 13-10-2018, 19:30:41
понял спасибо!
Название: Re: как правильно завершить транзакцию
Отправлено: Вильдар от 13-10-2018, 19:39:53
А, как вам такой метод расширения:
Код - 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. });
Название: Re: как правильно завершить транзакцию
Отправлено: Дмитрий Загорулькин от 13-10-2018, 21:30:43
А, как вам такой метод расширения:
Вильдар, изящно! Я бы, правда, по-другому бы сделал - не люблю объёмные лямбда-выражения:
Код - 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.  
Название: Re: как правильно завершить транзакцию
Отправлено: avc от 14-10-2018, 00:11:20
Жесть. Такой изврат ради того, чтоб не писать tr.Commit () ?! Вы серьезно считаете что это проще?  Или я живу в другой вселенной....
Название: Re: как правильно завершить транзакцию
Отправлено: Александр Ривилис от 14-10-2018, 00:46:38
Жесть. Такой изврат ради того, чтоб не писать tr.Commit () ?! Вы серьезно считаете что это проще?  Или я живу в другой вселенной....
Ты не прав. Когда нужно чтобы в любом случае выполнился Commit с учетом всех возможных исключений - это идеальный вариант.
IMHO идея Autodesk'овцев что при Transaction.Dispose() выполняется откат транзакции если не выполнен Transaction.Commit мне кажется в корне неправильным.
Название: Re: как правильно завершить транзакцию
Отправлено: Вильдар от 14-10-2018, 10:28:27
Дмитрий Загорулькин, да, тоже такое сделал сначала. Но, потом убрал, т.к. при исключениях все равно будет вызван Commit(), мне кажется это не хорошо.
Название: Re: как правильно завершить транзакцию
Отправлено: Дмитрий Загорулькин от 14-10-2018, 18:02:15
Жесть. Такой изврат ради того, чтоб не писать tr.Commit () ?! Вы серьезно считаете что это проще?  Или я живу в другой вселенной....
Ну да. Голова не болит - поставил я Commit или нет? Иногда, например, если полученный объект не соответствует критериям, то ставишь return и выходишь из метода задолго до конца блока using транзакции. В этом случае надо тоже не забыть перед return Commit сделать. А таких мест может быть несколько, нужно держать в голове всё время эту особенность с Commit, концентрироваться на этом. А вот такие вот "извраты" позволяют меньше уделять внимания этим мелочам и больше концентрироваться на непосредственно реализации задачи. Можно сказать, что эти "извраты" - это обёртки, позволяющий сгладить некоторые огрехи AutoCAD API. Со временем, таких обёрток довольно много набирается. Методы со встроенными проверками. Методы, которые учитывают различные особенности, с которыми столкнулся в прошлом. Методы, которые просто упрощают взаимодействие с API. И т.п. Посади меня сейчас писать приложение "с нуля" без использования моих вспомогательных библиотек - я буду себя чувствовать крайне неуютно.
Но, потом убрал, т.к. при исключениях все равно будет вызван Commit(), мне кажется это не хорошо.
Возможно. Как-то даже не задумывался об этом. А при исключении не всё равно что в итоге будет: Commit или Abort? У меня обычно с высокой вероятностью далее будет Fatal Error  :)
Название: Re: как правильно завершить транзакцию
Отправлено: Вильдар от 14-10-2018, 18:51:14
Про фатал метко подмечено  :'(
Если до исключения, будут созданы какие-то объекты, но до логического конца команда не дошла. То, правильнее, наверно, откатить все изменения.
А "умная" транзакция, пропустив исключение дальше, вызовит Commit().
Название: Re: как правильно завершить транзакцию
Отправлено: avc от 14-10-2018, 21:07:48
Что часто приходится выходить из процедуры до финального коммита - это однозначно так. А вот подменять дефолтное поведение на любое свое - это отличный способ подложить себе грабли на будущее. ИМХО наилучший вариант - явно написать, что делать транзакции в данном случае - аборт или коммит. в случае исключения - конечно аборт. и правильно его сделали дефолтным. одними граблями меньше. не завидую тем,  кому придется дописывать что-то на базе вашего кода с такими "улучшайзерами". это как перегрузить == на !=
А про то, что кучи своих вспомагательных классов и взяких хелперов здорово ускоряют работу - тут я конечно ЗА. спорить не о чем
Название: Re: как правильно завершить транзакцию
Отправлено: Дмитрий Загорулькин от 14-10-2018, 21:47:20
А вот подменять дефолтное поведение на любое свое - это отличный способ подложить себе грабли на будущее.
А где тут подмена? В варианте от Вильдара всё работает точно так же, как если бы не использовался вспомогательный метод. В моём, с учётом замечания Вильдара, возможно что нет. Если это критично - значит пользуемся его вариантом.
не завидую тем,  кому придется дописывать что-то на базе вашего кода с такими "улучшайзерами"
А в чём проблема? Заглянуть в определение метода расширения и понять как он работает - дело пары минут. Думаю, что наоборот даже - можно позавидовать. Человек увидит, как можно легко упростить себе жизнь использованием таких обёрток и возьмёт себе на вооружение.
это как перегрузить == на !=
По мне - это совсем неподходящее сравнение. В данном случае логика работы никак не подменяется на противоположную, просто объединяются несколько операций в одну.