Понятие ObjectId
Каждый содержащийся в базе данных объект связан с несколькими уникальными идентификаторами:
- Entity handle;
- ObjectId;
- Instance pointer (указатель на объект);
Наиболее распространенным способом получения доступа к объекту является ObjectId. Идентификаторы на основе ObjectId также удобны, когда ваш проект использует одновременно .NET API и ActiveX (COM) API. В случае создания AutoLISP-функций предпочтительнее будет использовать Handle-идентификаторы.
Указатели (свойство UnmanagedObject) уместно применять только при вызове функций из ARX-API через механизм P/Invoke; Идентификаторы-handle сохраняются между сеансами AutoCAD для каждого из чертежей, поэтому они являются лучшим способом доступа к объектам, если необходимо экспортировать информацию о чертеже во внешний файл, который впоследствии может быть использован для обновления чертежа. ObjectId объекта в базе данных существует только пока база данных загружена в память. После закрытия базы данных ObjectId, присвоенный объекту, перестаёт существует и может стать другим для данного объекта при следующем открытии базы данных.
Получение ObjectId
Перед тем как работать с каким-либо объектом необходимо получить его идентификатор ObjectId; он будет назначен существующему объекту в базе данных модели, при открытии файла чертежа. Новые объекты получают ObjectId после своего создания (при добавлении в модель AddEntityToDatabase). Есть 2 основных пути получения ObjectId для существующих объектов в БД чертежа:
-
Использовать соответствующие свойства у объектов БД чертежа: например, свойство Database.Clayer возвращает ObjectId активного слоя чертежа;
-
Использовать итеративный перебор таблицы символов, например, таблицы слоев Layer;
Открытие объекта
Как только ObjectId был получен, можно использовать функцию GetObject для открытия объекта из-под транзакции, связанного с данным ObjectId. Объект может быть открыт в одном из следующих режимов:
-
Read. Объект открыт для чтения;
-
Write. Объект открывается для записи (также для чтения), если он не был открыт ранее;
-
Notify. Объект открывается для информирования в случаях, когда объект закрыт или уже открыт для чтении или записи, но когда не был открыт для данного режима Notify. Этот режим предназначен для использования в тех случаях, когда объект может изменять себя из собственного кода, например при определении пользовательского объекта, который не поддерживается управляемым AutoCAD .NET API;
Следует открывать объект в том режиме, для которого нужен соответствующий доступ. Несмотря на удобство режима Write для чтения и записи, при его использовании затрачивается больше ресурсов на стороне нативного кода. Если вы не уверены, что открываемый объект : это тот, с которым вы хотите работать, откройте его сперва в режиме чтения, а затем переведите объект из режима чтения в режим записи. Дополнительные сведения об изменении способа открытия объекта см. в разделе. Обе функции GetObject и Open возвращают объект (подробнее о каждой см. раздел). При разработке на C# вам необходимо будет дополнительно приводить тип возвращаемого объекта к нужному классу с помощью модификатора as.
При работе с Dynamic Runtime Language (DLR) вам нет необходимости беспокоиться, открыт объект дли записи или для чтения. Открытие объекта происходит автоматически и незаметно для пользователя, как и процесс фиксации изменений, внесенных в объект, без использования транзакций. Подробнее см. статью. В следующих примерах показано, как получить запись LayerTableRecord для нулевого слоя текущей базы данных. В следующем примере транзакция удаляется вручную после того, как она больше не нужна.
Document acCurDb = Application.DocumentManager.MdiActiveDocument.Database;
Transaction acTrans = acCurDb.TransactionManager.StartTransaction();
LayerTableRecord acLyrTblRec;
acLyrTblRec = acTrans.GetObject(acCurDb.LayerZero,
OpenMode.ForRead) as LayerTableRecord;
acTrans.Dispose();
В следующем примере используется оператор using для утилизации транзакции после того, как она больше не нужна. Конструкция using является предпочтительной.
Document acCurDb = Application.DocumentManager.MdiActiveDocument.Database;
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
LayerTableRecord acLyrTblRec;
acLyrTblRec = acTrans.GetObject(acCurDb.LayerZero,
OpenMode.ForRead) as LayerTableRecord;
}