拡張ストレージ

拡張ストレージ

Revit API を使用すると、クラスに似た独自のスキーマ データ構造を作成し、そのインスタンスを Revit モデルの任意の要素にアタッチすることができます。スキーマベースのデータは Revit モデルに保存され、より上位レベルの、メタデータによって拡張された、オブジェクト指向のデータ構造となります。スキーマ データは、すべてのユーザに読み取り/書き込みを許可、特定のアプリケーション ベンダーのみに許可、ベンダーの特定のアプリケーションのみに許可するように設定できます。

Revit の要素にデータを保存するには次の手順が必要です。

  1. 新しいスキーマを作成して名前を付ける
  2. スキーマの読み取り/書き込みアクセスを設定する
  3. スキーマのデータの 1 つまたは複数のフィールドを定義する
  4. スキーマに基づいてエンティティを作成する
  5. エンティティのフィールドに値を割り当てる
  6. エンティティを Revit 要素に関連付ける

スキーマと SchemaBuilder

拡張ストレージを作成するための最初の手順は、スキーマの定義です。スキーマは、オブジェクト指向プログラミング言語のクラスに似ています。新しいスキーマを作成するには、SchemaBuilder クラスのコンストラクタを使用します。SchemaBuilder はスキーマを作成するためのヘルパー クラスです。SchemaBuilder を使用してスキーマを作成した後、Schema クラスを使用してスキーマのプロパティにアクセスします。この段階で、スキーマは編集できなくなります。

SchemaBuilder コンストラクタはスキーマを識別するために使用する GUID を取りますが、スキーマ名も必要となります。スキーマを作成した後、SchemaBuilder.SetSchemaName()を呼び出して、スキーマに分かりやすい識別子を割り当てます。スキーマ名は、エラー メッセージでスキーマを識別するのに便利です。

スキーマに関連付けられているエンティティの読み取りと書き込みのレベルは個別に設定することができます。Public、Vendor、Application のオプションがあります。読み取りまたは書き込みアクセス レベルが Vendor に設定されている場合、スキーマのエンティティにアクセスする可能性のあるサードパーティ ベンダーの VendorId を設定する必要があります。読み取りまたは書き込みアクセス レベルが Application に設定されている場合、スキーマのエンティティにアクセスする可能性のあるアプリケーションまたはアドインの GUID を設定する必要があります。

注: スキーマはドキュメントに保存され、任意の Revit API アドインはドキュメント内の使用可能なスキーマだけでなく、スキーマのデータの一部を読み込む場合があります。ただし、スキーマのフィールドへのアクセスは、スキーマに定義されている読み取りアクセスに基づいて制限され、特定の要素に保存されているエンティティ内の実際のデータは、定義時にスキーマに設定した読み取りと書き込みアクセスに基づいて制限されます。

フィールドと FieldBuilder

スキーマを作成した後、フィールドを定義することができます。フィールドはクラスのプロパティに似ています。名前、ドキュメント、値タイプと単位のタイプを持ちます。フィールドは単純タイプ、配列、マップに設定できます。次の単純データ タイプが許可されています。

タイプ

既定値

int

0

short

0

byte

0

double

0.0

float

0.0

bool

false

string

空の文字列("")

GUID

Guid.Empty {00000000-0000-0000-0000-000000000000}

ElementId

ElementId.InvalidElementId

Autodesk.Revit.DB.XYZ

(0.0,0.0,0.0)

Autodesk.Revit.DB.UV

(0.0,0.0)

さらに、フィールドを Autodesk.Revit.DB.ExtensibleStorage.Entity タイプとすることもできます。つまり、別のスキーマのインスタンス(SubSchema や SubEntity と呼ばれる)とすることもできます。このタイプのフィールドの既定値は null スキーマを持つ Entity で、GUID は Guid.Empty となります。

単純フィールドは SchemaBuilder.AddSimpleField()メソッドを使用して作成することができ、フィールドの名前とタイプを指定します。AddSimpleField()は、フィールドを定義するためのヘルパー クラスである FieldBuilder を返します。フィールドのタイプを Entity として指定した場合は、FieldBuilder.SetSubSchemaGUID()を使用して、このフィールドに保存するエンティティのスキーマの GUID を指定します。

含まれる値の名前とタイプを指定して、スキーマに値の配列を持つフィールドを作成するには、SchemaBuilder.AddArrayField()メソッドを使用します。配列フィールドには単純フィールドと同じタイプをすべて指定することができます。

含まれる値の名前、キーのタイプ、値のタイプを指定して、スキーマに編成されたキー値マップを持つフィールドを作成するには、SchemaBuilder.AddMapField()メソッドを使用します。サポートされる値のタイプは単純フィールドのタイプと同じです。サポートされるキーのタイプは、int、short、byte、string、bool、ElementId、GUID に限定されます。

SchemaBuilder を使用してスキーマを完成させると、FieldBuilder を使用したフィールドの編集はできなくなります。この段階で、Schema クラスでは名前でフィールドを取得するメソッドや、スキーマ内に定義されているすべてのフィールドのリストを取得するメソッドを使用できます。

エンティティ

スキーマのすべてのフィールドを定義した後、SchemaBuilder.Finish()が完成したスキーマを返します。そのスキーマを使用すれば、新しいエンティティを作成できます。スキーマの各フィールドに対しては、フィールドと値(そのタイプはフィールド タイプによって異なる)を取る Entity.Set()を使用して値を保存できます。エンティティの適用可能なすべてのフィールドを設定した後、Element.SetEntity()メソッドを使用して要素に割り当てることができます。

後でデータを取得するには、Element.GetEntity()を呼び出して対応するスキーマに渡します。該当するスキーマに基づくエンティティが要素に保存されていない場合は、無効なエンティティが返されます。有効なエンティティが返されたことを確認するには、Entity.IsValid()メソッドを呼び出します。エンティティのフィールド値は、Entity.Get()メソッドを使用することで取得できます。

要素に保存されているエンティティを確認するには、Element.GetEntitySchemaGuids()メソッドを使用します。このメソッドは要素のエンティティのスキーマ GUID を返します。スキーマ GUID を静的メソッド Schema.Lookup()とともに使用すると、対応するスキーマを取得できます。

次は、これらの手順を 1 つにまとめた例です。

コード領域 22-9: 拡張ストレージ

// Create a data structure, attach it to a wall, populate it with data, and retrieve the data back from the wall
void StoreDataInWall(Wall wall, XYZ dataToStore)
{
        Transaction createSchemaAndStoreData = new Transaction(wall.Document, "tCreateAndStore");
        createSchemaAndStoreData.Start();
        SchemaBuilder schemaBuilder = 
                new SchemaBuilder(new Guid("720080CB-DA99-40DC-9415-E53F280AA1F0"));
        schemaBuilder.SetReadAccessLevel(AccessLevel.Public); // allow anyone to read the object
        schemaBuilder.SetWriteAccessLevel(AccessLevel.Vendor); // restrict writing to this vendor only
        schemaBuilder.SetVendorId("ADSK"); // required because of restricted write-access
        schemaBuilder.SetSchemaName("WireSpliceLocation");
        // create a field to store an XYZ
        FieldBuilder fieldBuilder = 
                schemaBuilder.AddSimpleField("WireSpliceLocation", typeof(XYZ)); 
        fieldBuilder.SetUnitType(UnitType.UT_Length);
        fieldBuilder.SetDocumentation("A stored location value representing a wiring splice in a wall.");

        Schema schema = schemaBuilder.Finish(); // register the Schema object
        Entity entity = new Entity(schema); // create an entity (object) for this schema (class)
        // get the field from the schema
        Field fieldSpliceLocation = schema.GetField("WireSpliceLocation"); 
        // set the value for this entity
        entity.Set<XYZ>(fieldSpliceLocation, dataToStore, DisplayUnitType.DUT_METERS); 
        wall.SetEntity(entity); // store the entity in the element

        // get the data back from the wall
        Entity retrievedEntity = wall.GetEntity(schema);
        XYZ retrievedData = 
                retrievedEntity.Get<XYZ>(schema.GetField("WireSpliceLocation"),
                DisplayUnitType.DUT_METERS);
        createSchemaAndStoreData.Commit();  
}

拡張ストレージの利点

自己文書化と自己定義

フィールド、単位、サブエンティティ、説明文字列を追加してスキーマを作成するのは、データを保存する手段だからというだけではありません。これは、他のユーザの潜在的な資料となり、同じスキーマのエンティティを後で作成するとき、より簡単にできるようになります。

局所性の活用

スキーマのエンティティは要素ごとに保存されるため、アプリケーションが現在選択している梁のデータのみを必要としている場合、必ずしもドキュメント内のすべての拡張ストレージ データ(すべての梁ファミリ インスタンスのすべてのデータ)を読み込む必要はありません。これにより、よりターゲットを絞ったデータ アクセス コードが可能となり、全体のデータ アクセス パフォーマンスも改善します。