Открытие объектов без использования транзакции.

Автор Тема: Открытие объектов без использования транзакции.  (Прочитано 40185 раз)

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

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Ха. Хотя я был уверен, что Андрей Бушман прав, но оказалось что это не так.
...
Т.е. поведение OpenCloseTransaction сделали подобным поведению обычной Transaction.
Обозначенную информацию я взял не с потолка, а из блогов Автодеск. Вы хотите сказать не "сделали", а "переделали"? Если "да", то в какой версии Автокада это произошло. Сам проверить не могу, т.к. в ближайшие несколько дней доступа к Автокаду у меня нет.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Уберу эту конструкцию, хотя, думаю, что на работе кода это никак не скажется.
Это 100% лишняя конструкция, которая приводит или к повторному .Close объекта или к последовательному вызову .Abort, а затем .Close объекта, что мягко говоря плохо.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Т.е. поведение OpenCloseTransaction сделали подобным поведению обычной Transaction
Сейчас проверил в 2009-м Acade - поведение аналогичное. Ищу в Интернете источник информации, где я прочитал об этом "отличии"...

Пока в обозначенной выше записи блога подправил текст, зачеркнув ошибку и добавив пояснение:
Цитировать
Обратите внимание, что у Transaction и у OpenCloseTransaction похожее использование, но разное действие по умолчанию:
у Transaction, по умолчанию вызывается метод Abort(), тем самым отменяя все изменения, а у OpenCloseTransaction по умолчанию вызывается метод Close(), тем самым наоборот - сохраняя все выполненные изменения.
Зачёркнута ошибочная информация, выяснилось здесь.
« Последнее редактирование: 16-09-2014, 12:37:31 от Андрей Бушман »

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Позволил себе немного модифицировать исходный код Александра Наумовича. Это маленький пример того, как можно безболезненно (не внося существенных правок в код) менять способ редактирования объектов (с использованием транзакции или же с её эмуляцией):

Код - C# [Выбрать]
  1. // © Андрей Бушман, 2014
  2. // Commands.cs
  3. using System;
  4. using System.Collections.Generic;
  5.  
  6. #if AUTOCAD
  7. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  8. using Ap = Autodesk.AutoCAD.ApplicationServices;
  9. using Db = Autodesk.AutoCAD.DatabaseServices;
  10. using Ed = Autodesk.AutoCAD.EditorInput;
  11. using Rt = Autodesk.AutoCAD.Runtime;
  12. #endif
  13.  
  14. [assembly: Rt.CommandClass(typeof(Bushman.CAD.Sandbox.TransactionGames.Commands))]
  15.  
  16. namespace Bushman.CAD.Sandbox.TransactionGames {
  17.     public sealed class Commands {
  18.  
  19.         /// <summary>
  20.         /// За основу взят код Александра Ривилиса:
  21.         /// http://adn-cis.org/forum/index.php?topic=940.msg4166#msg4166
  22.         /// </summary>
  23.         [Rt.CommandMethod("TestOpenClose")]
  24.         public void TestOpenClose() {
  25.             Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  26.             Db.Database db = doc.Database;
  27.             Db.TransactionManager tm = db.TransactionManager;
  28.             Ed.Editor ed = doc.Editor;
  29.  
  30.             Ed.PromptKeywordOptions pso = new Ed.PromptKeywordOptions(
  31.                 "Использовать транзакцию?");
  32.             String yes = "Yes";
  33.             String no = "No";
  34.             pso.Keywords.Add(yes);
  35.             pso.Keywords.Add(no);
  36.             pso.AppendKeywordsToMessage = true;
  37.             pso.Keywords.Default = yes;
  38.  
  39.             Ed.PromptResult pr = ed.GetKeywords(pso);
  40.             if (Ed.PromptStatus.OK != pr.Status) {
  41.                 ed.WriteMessage("Выполнение команды прервано.\n");
  42.             }
  43.  
  44.             // С помощью этой переменной можно управлять тем, будет ли работа
  45.             // выполняться с использованием транзакции или же с её эмуляцией.
  46.             // Т.о. в одном месте изменив значение переменной transaction_use
  47.             // можно одним махом изменить способ редактирования объектов сразу
  48.             // во многих местах исходного кода (в данном примере показано одно
  49.             // такое место):
  50.             Boolean transaction_use = pr.StringResult == yes;
  51.             Func<Db.Transaction> get_tr = null;
  52.  
  53.             if (transaction_use)
  54.                 get_tr = tm.StartTransaction;
  55.             else
  56.                 get_tr = tm.StartOpenCloseTransaction;
  57.  
  58.             // Т.к. OpenCloseTransaction наследуется от Transaction, то можно
  59.             // записать так:
  60.             using (Db.Transaction tr = get_tr()) {
  61.  
  62.                 Db.Circle cr = new Db.Circle();
  63.                 cr.SetDatabaseDefaults(db);
  64.                 cr.Radius = 10;
  65.  
  66.                 Db.BlockTableRecord mspace = tr.GetObject(db.CurrentSpaceId,
  67.                     Db.OpenMode.ForWrite) as Db.BlockTableRecord;
  68.                 mspace.AppendEntity(cr);
  69.                 tr.AddNewlyCreatedDBObject(cr, true);
  70.                 // Если это строка закомментарена, то Круг не появляется:
  71.                 tr.Commit();
  72.             }
  73.         }
  74.     }
  75. }
« Последнее редактирование: 16-09-2014, 15:53:45 от Андрей Бушман »

Оффлайн Константин Соков

  • ADN Club
  • **
  • Сообщений: 56
  • Карма: 0
Почитал статьи указанные выше Александром Наумовичем. До этого использовал метод StartTransaction(), после прочтения решил использовать StartOpenCloseTransaction(). Приложение перестало работать. Есть подозрение что не работает из-за того что внутри метода, где используется StartOpenCloseTransaction() вызывается метод где используется StartTransaction(). Может такое быть?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Может такое быть?
Да. И именно потому что:
внутри метода, где используется StartOpenCloseTransaction() вызывается метод где используется StartTransaction().
Возьми себе за правило:
1) Не смешивать Transaction и OpenCloseTransaction.
2) Не использовать вложенные OpenCloseTransaction.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Константин Соков

  • ADN Club
  • **
  • Сообщений: 56
  • Карма: 0
Вызов метода из метода считается вложением? Появляется ошибка при использовании StartOpenCloseTransaction(), если использовать StartTransaction(), то все хорошо.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Вызов метода из метода считается вложением?
Нет конечно. Вложенная транзакция, это когда одна транзакция уже работает, а ты в это время создаёшь новую.
Ошибка у тебя из-за того что объект открыт ForRead, а должен быть ForWrite, т.к. ты его модифицируешь. Сообщение совершенно четко тебе об этом указывает.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
2) Не использовать вложенные OpenCloseTransaction.
А если я использую вложенные только для открытия на чтение?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А если я использую вложенные только для открытия на чтение?
Правильный подход! :) Если уровень вложенности не превышает 255 (эту цифру мы уже с тобой обсуждали), то всё нормально.
Вообще-то нормально будет даже если открывать на запись, но (!!!) если один и тот-же объект не открывается больше чем в одной транзакции. Короче говоря для OpenCloseTransaction работают те же правила, что описаны в Autodesk ObjectARX SDK Documents: Developer Guide > ObjectARX Introductory Concepts > ObjectARX Introductory Concepts > Database Objects > Opening and Closing Database Objects
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Константин Соков

  • ADN Club
  • **
  • Сообщений: 56
  • Карма: 0
Небольшой пример, просто вставка блока, с StartTransaction() - все хорошо, с StartOpenCloseTransaction() - ошибка. Не могу понять почему.
Код - C# [Выбрать]
  1.         static public BlockReference InsertBlock(string name, Point3d basepnt)
  2.         {
  3.             Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  4.             Database acDb = acDoc.Database;
  5.             Editor ed = acDoc.Editor;
  6.             BlockReference br = null;
  7.  
  8.             //using (Transaction trans = acDb.TransactionManager.StartOpenCloseTransaction())
  9.             using (Transaction trans = acDb.TransactionManager.StartTransaction())
  10.             {
  11.                 BlockTable bt = (BlockTable)acDb.BlockTableId.GetObject(OpenMode.ForWrite);
  12.                 BlockTableRecord btrSpace = trans.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
  13.  
  14.                 if (!bt.Has(name))
  15.                 {
  16.                     ed.WriteMessage("\nНе найдено опеределение блока \"" + name + "\"");
  17.                     return null;
  18.                 }
  19.  
  20.                 BlockTableRecord btrFind = (BlockTableRecord)bt[name].GetObject(OpenMode.ForWrite);
  21.                 br = new BlockReference(basepnt, btrFind.ObjectId);
  22.  
  23.                 btrSpace.AppendEntity(br);
  24.                 trans.AddNewlyCreatedDBObject(br, true);
  25.  
  26.                 trans.Commit();
  27.             }
  28.             return br;
  29.         }
  30.  

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Замени:
1)
Код - C# [Выбрать]
  1. BlockTable bt = (BlockTable)acDb.BlockTableId.GetObject(OpenMode.ForWrite);
на
Код - C# [Выбрать]
  1. BlockTable bt = (BlockTable)acDb.BlockTableId.GetObject(OpenMode.ForRead);
2)
Код - C# [Выбрать]
  1. BlockTableRecord btrFind = (BlockTableRecord)bt[name].GetObject(OpenMode.ForWrite);
на
Код - C# [Выбрать]
  1. BlockTableRecord btrFind = (BlockTableRecord)bt[name].GetObject(OpenMode.ForRead);
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Строки #11 и #20 в коде и сообщения #12 и #13 в этой теме ;)

Оффлайн Константин Соков

  • ADN Club
  • **
  • Сообщений: 56
  • Карма: 0
Замени:
1)
Код - C# [Выбрать]
  1. BlockTable bt = (BlockTable)acDb.BlockTableId.GetObject(OpenMode.ForWrite);
на
Код - C# [Выбрать]
  1. BlockTable bt = (BlockTable)acDb.BlockTableId.GetObject(OpenMode.ForRead);
2)
Код - C# [Выбрать]
  1. BlockTableRecord btrFind = (BlockTableRecord)bt[name].GetObject(OpenMode.ForWrite);
на
Код - C# [Выбрать]
  1. BlockTableRecord btrFind = (BlockTableRecord)bt[name].GetObject(OpenMode.ForRead);
Пробывал, результат один - StartTransaction() - работает, StartOpenCloseTransaction() - не работает
Строки #11 и #20 в коде и сообщения #12 и #13 в этой теме ;)
А это в моей ситуации самое разумное объяснение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
А это в моей ситуации самое разумное объяснение
Да. Я как-то не обратил внимание. Тем не менее исправить нужно и то, и другое.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение