Передача экземпляра класса Transaction как параметр метода

Автор Тема: Передача экземпляра класса Transaction как параметр метода  (Прочитано 5524 раз)

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

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

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Если я передам объект транзакции в параметр метода не нарвусь ли я на какие нибудь "подводные камни" при сбое в методе NewMethod()? Или лучше для каждого метода создавать свой экземпляр транзакции?

Пример кода:

   
Код - C# [Выбрать]
  1. class MyClass
  2.     {
  3.         void MyMethod()
  4.         {
  5.             using (Db.Transaction tr = db.TransactionManager.StartTransaction())
  6.             {
  7.                 NewMethod(tr);
  8.                 //...//
  9.                 tr.Commit();
  10.             }
  11.         }
  12.  
  13.         void NewMethod(Db.Transaction tr)
  14.         {
  15.             //...//
  16.             Ed.PromptEntityResult res = ed.GetEntity(options);
  17.             Db.BlockReference Shield_Ref = tr.GetObject(res.ObjectId, Db.OpenMode.ForRead, false, true) as Db.BlockReference;
  18.             //...//
  19.  
  20.         }
  21.     }

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 470
  • Карма: 63
GetEntity при открытой транзакции? хм...

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

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
Да можно передавать транзакцию.
Обычно стартую одну транзакцию на команду.
Можно открыть объект без транзакции:
Код - C# [Выбрать]
  1. ObjectId.GetObject()
При этом должна быть запущена транзакция.

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Можно открыть объект без транзакции
... и нарваться на сбои,  потому что никто не гарантирует, что объект открыт в МОЕЙ транзакции, а не каком-то другом потоке. Я не мало времени потратил убирая у себя в коде явные и неявные обращения к toptransaction. Да,  теперь почти все мелкие статические методы имеют лишний аргумент - транзакцию. А сложные открывают свою. Это захламляет код,  но повышает стабильность работы.

Оффлайн Александр Пекшев aka Modis

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
ИМХО. Транзакцию нужно открывать только тогда, когда вы собираетесь менять объект. И лучше всего область видимости (scope) вашей транзакции сделать по возможности минимальной. Открыть один раз где-то в начале - так себе идея.
А вообще все зависит от конкретной задачи и архитектуры кода

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

  • ADN OPEN
  • Сообщений: 40
  • Карма: 1
Александр Пекшев aka Modis, согласен с тобой. Я привёл абстрактный пример. Меня смущал вопрос, что когда программа передаёт управление NewMethod(), то в нём отсутствует Commit(). Как бы вела себя программа при неполадки в NewMethod()? Будут ли закрыты открытые объекты? Или может есть другие сюрпризы, о которых я не знаю. Но avc и Вильдар, мои сомнения сняли и передавать транзакцию в метод все таки можно.

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 470
  • Карма: 63
если в NewMethod будет ошибка - посыпится вся транзакция

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Но avc и Вильдар, мои сомнения сняли и передавать транзакцию в метод все таки можно.
Можно, можно. На то она и транзакция, чтоб откатить или применить сразу все изменения, не зависимо от того в каком методе они сделаны. Commit само собой должен быть в том методе, где создана транзакция, прямо перед ее уничтожением.

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

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
... и нарваться на сбои,  потому что никто не гарантирует, что объект открыт в МОЕЙ транзакции, а не каком-то другом потоке.
Что-то страшное.
Выполняется команда, в основном потоке.
Если не мудрить с потоками, то такая ситуация исключена.
Транзакцию нужно открывать только тогда, когда вы собираетесь менять объект.
А для чтения не нужно открывать транзакцию?

Оффлайн avc

  • ADN Club
  • *****
  • Сообщений: 805
  • Карма: 166
    • Мои плагины к Автокаду
Что-то страшное
Это МОЯ команда в одном потоке, а в это время Автокад по таймерам и событиям живет своей жизнью, открывает новые транзакции. И никто мне не обещает, что эту чужую транзакцию я не словлю в toptransaction. И попробуйте тогда угадать, кто первый уничтожит нужный мне объект, я или чужая транзакция... По факту отказ от обращений к toptransaction привел к исчезновению случайных сбоев во время закрытия транзакций, которые меня сильно доставали. Правда это были не фатальные ошибки, но совершенно непредсказуемые. Вот типичное сообщение о такой ошибке:

Error:
  Type: System.InvalidOperationException
  Message: Operation is not valid due to the current state of the object.
  Source: Acdbmgd
  TargetSite: Void CheckTopTransaction()

System.InvalidOperationException: Operation is not valid due to the current state of the object.
   at Autodesk.AutoCAD.DatabaseServices.Transaction.CheckTopTransaction()
   at Autodesk.AutoCAD.DatabaseServices.Transaction.DeleteUnmanagedObject()
   at Autodesk.AutoCAD.Runtime.DisposableWrapper.!DisposableWrapper()
   at Autodesk.AutoCAD.Runtime.DisposableWrapper.Dispose(Boolean A_0)
   at Autodesk.AutoCAD.Runtime.DisposableWrapper.Dispose()
   at ....

Если кто расскажет как использовать toptransaction и не выстрелить себе в ногу не нарваться на такие ошибки - буду премного благодарен.

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

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
Это МОЯ команда в одном потоке, а в это время Автокад по таймерам и событиям живет своей жизнью, открывает новые транзакции.
Команда выполняется в главном потоке приложения (единственном), при этом не допускаются обращения к апи автокада из других потоков.
Соответственно, по таймерам, в других потоках, нельзя запустить транзакцию и т.п.
Возможно нехорошие плагины этим занимаются.

С подобными ошибками, вроде, не сталкивался пока.

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 611
  • Карма: 155
    • ПГСу Бложик
Стырено тут: https://spiderinnet1.typepad.com/blog/2014/05/net-crash-autocad-14-new-dbobjectentity-but-not-dispose-of-it.html?cid=6a0153928ee38e970b01a73dc6316f970d#comment-6a0153928ee38e970b01a73dc6316f970d
Цитировать
>>How would you handle the case of something wrong after the New DBObject but before the Transaction.AddNewlyCreatedDBObject() then?<<
I prefer do not use transaction at all (as Fenton Webb: http://adndevblog.typepad.com/autocad/2012/06/creating-a-polyline3d-without-using-transactions.html )
Posted by: Alexander Rivilis | 05/18/2014 at 07:14 AM
Можно открыть объект без транзакции:
   
Код - C# [Выбрать]
  1. ObjectId.GetObject()
Я думаю без транзакции более правильно так:
ObjectId.Open(OpenMode.ForRead)

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

  • ADN Club
  • ****
  • Сообщений: 405
  • Карма: 77
  • Skype: vildar82
Я думаю без транзакции более правильно так:
ObjectId.Open(OpenMode.ForRead)
Имелось ввиду без передачи объекта транзакции явно. Но с запущенной транзакцией.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Если я передам объект транзакции в параметр метода не нарвусь ли я на какие нибудь "подводные камни" при сбое в методе NewMethod()? Или лучше для каждого метода создавать свой экземпляр транзакции?
Именно из-за передачи транзакции в метод как параметра проблем не будет. А вот из-за использования транзакции в некоторых случаях могут возникнуть проблемы. Но есть шанс, что вы на них никогда не наткнётесь.
Транзакцию нужно открывать только тогда, когда вы собираетесь менять объект.
Не совсем согласен с жёсткостью формулировки. Почему именно нужно? Я, например, очень часто и объекты изменяю без транзакции. И, в то же время, для чтения свойств в какой-нибудь простой команде использую транзакции.
А вообще все зависит от конкретной задачи и архитектуры кода
Вот тут абсолютно согласен!

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 533
  • Карма: 117
Если я передам объект транзакции в параметр метода не нарвусь ли я на какие нибудь "подводные камни" при сбое в методе NewMethod()? Или лучше для каждого метода создавать свой экземпляр транзакции?
По идее блок USING гарантирует вызов метода Dispose в любом случае, даже в случае ошибки в методе NewMethod(). Однако он не спасет от ошибок работы с Database и DbObjects, которые частенько "убивают" AutoCAD, делая дальнейшие вызовы Commit и Dispose у транзакции бессмысленными. (по крайней мере я не доверяю работе AutoCAD после fatal error и не сохраняю результат работы.)

Т.е. разделяя работу с транзакцией на методы, на мой взгляд ты ничего не потеряешь в стабильности.

А вот создавать или нет для каждого метода свой экземпляр транзакции, зависит от логики приложения. Лишние создание/закрытие транзакций могут ощутимо просадить производительность твоего приложения.