Skip to content

Entity.getMetaData throws Error: Cannot get Metadata #8288

@MichaelSwigerAtBentley

Description

@MichaelSwigerAtBentley

Describe the bug

When calling entity.getMetaData on a relationship, throws an error 'Cannot get metadata'.
This is because getMetaData only expects an EntityClass to be queried, not an EntityRelationship. getMetaData() should support both.

Entity._metadata is also restricted to be an EntityClass when it could potentially be an EntityRelationship as well.

To Reproduce

Test to reproduce the behavior:

  it("should get metadata for a relationship", async () => {
    const imodelPath = IModelTestUtils.prepareOutputFile("IModel", "relationshipMetadata.bim");
    const imodel = SnapshotDb.createEmpty(imodelPath, { rootSubject: { name: "relationshipMetadata" } });

    const partitionId = imodel.elements.insertElement({
      classFullName: "BisCore:PhysicalPartition",
      model: IModel.repositoryModelId,
      parent: {
        relClassName: "BisCore:SubjectOwnsPartitionElements",
        id: IModel.rootSubjectId,
      },
      code: new Code({
        spec: imodel.codeSpecs.getByName(BisCodeSpec.informationPartitionElement).id,
        scope: IModel.rootSubjectId,
        value: "physical model",
      }),
    });

    for await (const row of imodel.createQueryReader(`SELECT * FROM bis.Element LIMIT ${1}`)) {
      const relId = imodel.relationships.insertInstance({
        classFullName: "BisCore:ElementHasLinks",
        sourceId: partitionId,
        targetId: row.ECInstanceId,
      });
      const relationship = imodel.relationships.getInstance("BisCore:ElementHasLinks", relId);
      const metadata = relationship.getMetaData();
      assert.isDefined(metadata, metadata should be defined);
    }
    imodel.close();
  });

Expected behavior

Should not error.

Additional context

The issue cause is similar to: #8231.
Additional discussion on this topic can be found here: #8277

Discussion from PR

After some discussion with Affan, I feel we should do something like this:

export class Entity {
public async getMetaData(): Promise<EntityClass | RelationshipClass> {
const ecClass = await this.iModel.schemaContext.getSchemaItem(this.schemaItemKey, ECClass);
if (EntityClass.isEntityClass(ecClass) || RelationshipClass.isRelationshipClass(ecClass)) {
return ecClass;
}
throw new Error(Cannot get metadata for ${this.classFullName});
}
}

export class Element extends Entity {
public async override getMetaData(): Promise {
const entity = await this.iModel.schemaContext.getSchemaItem(this.schemaItemKey, EntityClass);
if (entity !== undefined) {
return entity;
}
throw new Error(Cannot get metadata for ${this.classFullName});
}
}

export class Relationship extends Entity {
public async override getMetaData(): Promise {
const relationship = await this.iModel.schemaContext.getSchemaItem(this.schemaItemKey, RelationshipClass);
if (relationship !== undefined) {
return relationship;
}
throw new Error(Cannot get metadata for ${this.classFullName});
}
}
However, that is a breaking change. It will probably not affect anybody because everybody is working with subclasses of Entity. Still, we need to make sure we override this properly on every subclass.

The problem stems from the fact that the class hierarchy between ecschema-metadata and core-backend are different. ecschema uses ECClass as a common base class for entity and relationship while backend has relationship directly derive from entity.

It does kind of look like the only way to fix getMetaData is to break the API.

It's a real shame that we've capitalized the D in MetaData

I guess we could deprecate getMetaData and replace with a correct getMetadata function.

Metadata

Metadata

Labels

ecdbECDb and ECSQL related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions