Extensible Storage Helpers in BimRv

Evgeniy Tikhonov

June 27, 2019

The Extensible Storage mechanism allows storing user data directly in model elements. This mechanism is not used by and does not affect parameters of a project or family. Information can be stored in almost any element of the model. For doing this, user data should be described by the following objects:

  • Field — Contains data name, type, and unit information and is used as the key to access corresponding data in an entity.
  • Schema — A collection of data field objects.
  • Entity — An object containing data corresponding to a schema that can be inserted into an element.

BimRv provides functionality to create and work with schema-based data structures. This functionality contains schema and field builders and helpers:

  • OdBmSchemaBuilder — Allows creation of schema definitions.
  • OdBmFieldBuilder —A helper class used with OdBmSchemaBuilder when creating a new field.
  • OdBmESEntityHelper — A helper class used to access field values of an existing extensible entity.
  • OdBmESSchemaHelper — Allows reading of existing schema attributes and fields.
  • OdBmESFieldHelper — A helper class used with OdBmESSchemaHelper when reading field attributes and definitions.

The following data types are supported:

  • bool
  • OdInt16
  • OdInt32
  • double
  • float
  • OdString
  • OdGuid
  • OdBmObjectId
  • OdGePoint2d
  • OdGePoint3d
  • OdArray
  • OdMap (all types are supported for keys except double, float, OdGePoint2d and OdGePoint3d)
  • OdBmObject (an instance of another schema)

Using attributes, a schema can be configured to restrict access for reading and/or writing for all users, a specific application vendor, or a specific application from a vendor.

The next steps describe simple usage of ExtensibleStorage.

1. Create a storage description

To create a new schema, use OdBmSchemaBuilder.

OdBmESSchemaBuilder schemaBuilder(pDb);
  schemaBuilder.setSchemaName(L"WireSpliceLocation")
      .setSchemaGUID(OdGUID("720080CB-DA99-40DC-9415-E53F280AA1F0"))
      .setVendorId(L"BimRv")
      .setDocumentation(L"WireSpliceLocation schema")
      .setReadAccessLevel(OdBm::ESSchemaAccessLevel::Public)
      .setWriteAccessLevel(OdBm::ESSchemaAccessLevel::Public);

To create fields for the storage, use the OdBmESFieldBuilder class.

It contains methods to set field attributes, such as:

  • OdBmESFieldBuilder& setDocumentation(const OdString&); — The description of the field.
  • OdBmESFieldBuilder& setSubSchemaGUID(const OdGUID&); — The GUID of the schema describing the subentity stored in the Field.
  • OdBmESFieldBuilder& setUnitType(const OdBm::UnitType::Enum); — The type of units represented by values stored in the field.

Create one array field and one map field:

schemaBuilder.addSimpleField<bool>(L"BooleanField")
      .setDocumentation(L"Boolean value");
  schemaBuilder.addSimpleField<OdGePoint3d>(L"XYZField")
      .setUnitType(OdBm::UnitType::UT_Length)
      .setDocumentation(L"XYZ value");
  schemaBuilder.addArrayField<OdGUID>(L"GUIDArrayField")
      .setDocumentation(L"GUID array value");

  schemaBuilder.addMapField<OdString, OdString>(L"StringMapField")
      .setDocumentation(L"Map value");

Names of the fields are used to access field data for writing and reading the values. After defining all fields in the schema, call the “finish” method to finish the schema builder.

OdTfClass* pSchema = schemaBuilder.finish();
OdBmObjectPtr pESEntity = OdBmDynamicObject::createObject(pSchema);

Field attributes, as well as schema attributes such as unit type, name and documentation, can not be changed after creation.

2. Set values

Use the OdBmESEntityHelper class to set values to the entity fields, for example:

OdBmESEntityHelper helper(pESEntity);

  helper.set<bool>(L"BooleanField", true);
  helper.set<OdGePoint3d>(L"XYZField", OdGePoint3d(20., 21., 22.),                                     OdBm::DisplayUnitType::DUT_METERS);

  OdArray<OdGUID> guids;
  guids.push_back(OdGUID("60E23C30-169B-4C46-BD2B-DC9FC476FD09"));
  guids.push_back(OdGUID("1BAD71AA-137E-4519-8D9B-B0ED1672D1BF"));
  helper.set<OdArray<OdGUID> >(L"GUIDArrayField", guids);

  OdBmMap<OdString, OdString> stringMap;
  stringMap[L"key1"] = L"value1";
  stringMap[L"key2"] = L"value2";
  helper.set<OdBmMap<OdString, OdString> >(L"StringMapField", stringMap);

The display unit type parameter is used for data types float, double, OdGePoint3d, and OdGePoint2d only and sets unit type for the field. No conversions are performed inside this method.

Use clone() in OdBmESEntityHelper.set for OdBmObjectPtr, for example:

helper.set<OdBmObjectPtr> (L"EntityField", pESEntity->clone());

The template parameter of set<> must exactly match the type of field (specified when creating the schema).

3. Storing data

Applications can attach instances of the schema to any element in a model. To avoid locking elements in shared projects, it is better to use the special element OdBmDataStorage.

OdBmDataStoragePtr pDataStorageElem = OdBmDataStorage::createObject();
    pDataStorageElem->setName(L"DataStorageElem");
    pDb->addElement(pDataStorageElem);

    pDataStorageElem->upgradeOpenMode();
    pDataStorageElem->setESEntity(pESEntity);
    pDataStorageElem->downgradeOpenMode();

4. Read the storage

OdBmObjectPtr pESEntity =
        pDataStorageElem->getESEntity(OdGUID(L"720080CB-DA99-40DC-9415-E53F280AA1F0")); 
   OdBmESEntityHelper helper(pESEntity);

   bool b = helper.get<bool>(L"BooleanField");	
   OdGePoint3d xyz = helper.get<OdGePoint3d>(L"XYZField",
     OdBm::DisplayUnitType::DUT_DECIMETERS);

The display unit type parameter in the get<> method is used to convert data into desired units, for example, xyz for the value set previously to the field is equal to OdGePoint3d(200., 210., 220.);


OdArray<OdGUID> guids = helper.get<OdArray<OdGUID> >(L"GUIDArrayField");
   OdBmMap<OdString, OdString> strings =
     helper.get<OdBmMap<OdString, OdString> >(L"StringMapField");

5. Read information

To read the recorded information, you need to get the model element and determine the storage GUID and field names.

To get schemas in a database, use the static listSchemas method of OdBmESSchemaHelper:

std::set<OdGUID> schemas = OdBmESSchemaHelper::listSchemas(pDb);

To get elements in a database that are related to the schema, use the static getElements method:

OdBmObjectIdArray objects = OdBmESSchemaHelper::getElements(guid, pDb);

You can also retrieve information regarding fields using OdBmESFieldHelper, for example:

OdBmESFieldHelper fieldHelper(helper.getField(L"BooleanField"));

It contains methods to assess field attributes, such as:

  • getDocumentation() — Description of the field.
  • getFieldName() — Name of the field.
  • getContainerType() — Returns the type of the field: simple field containing one value or a container of multiple values.
  • getEntryIndex() — Returns the index of the field.
  • getSubSchemaGUID() — GUID of the schema describing the subentity stored in this field.
  • getUnitType() — Type of units represented by values stored in this field.

OdBmESSchemaHelper helps get information regarding the schema:

OdBmESEntityHelper helper(pESEntity);
OdBmESSchemaHelper schHelper(helper.getSchema());

The helper has the following methods:

  • getDocumentation() — The description of the schema.
  • getVendorId() — The string ID of the third-party vendor that can access entities of this schema under the vendor access level.
  • getSchemaName() — The name of the schema.
  • getSchemaGUID() — The identifier of the schema.
  • getReadAccessLevel() — Read access level of the schema.
  • getWriteAccessLevel() — Write access level of the schema.