@itwin/core-backend 5.14.0-dev.9 → 5.15.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/CHANGELOG.md +38 -1
  2. package/lib/cjs/ChangesetReader.d.ts +1 -1
  3. package/lib/cjs/ChangesetReader.js +2 -2
  4. package/lib/cjs/ChangesetReader.js.map +1 -1
  5. package/lib/cjs/ChangesetReaderTypes.d.ts +4 -1
  6. package/lib/cjs/ChangesetReaderTypes.d.ts.map +1 -1
  7. package/lib/cjs/ChangesetReaderTypes.js +3 -0
  8. package/lib/cjs/ChangesetReaderTypes.js.map +1 -1
  9. package/lib/cjs/ECDb.d.ts +63 -6
  10. package/lib/cjs/ECDb.d.ts.map +1 -1
  11. package/lib/cjs/ECDb.js +62 -6
  12. package/lib/cjs/ECDb.js.map +1 -1
  13. package/lib/cjs/ECSqlStatement.d.ts +2 -2
  14. package/lib/cjs/ECSqlStatement.js +2 -2
  15. package/lib/cjs/ECSqlStatement.js.map +1 -1
  16. package/lib/cjs/Element.d.ts.map +1 -1
  17. package/lib/cjs/Element.js +6 -3
  18. package/lib/cjs/Element.js.map +1 -1
  19. package/lib/cjs/IModelDb.d.ts +12 -10
  20. package/lib/cjs/IModelDb.d.ts.map +1 -1
  21. package/lib/cjs/IModelDb.js +26 -12
  22. package/lib/cjs/IModelDb.js.map +1 -1
  23. package/lib/cjs/SchemaSync.d.ts +2 -2
  24. package/lib/cjs/SchemaSync.d.ts.map +1 -1
  25. package/lib/cjs/SchemaSync.js +2 -2
  26. package/lib/cjs/SchemaSync.js.map +1 -1
  27. package/lib/cjs/SqliteChangesetReader.d.ts +16 -8
  28. package/lib/cjs/SqliteChangesetReader.d.ts.map +1 -1
  29. package/lib/cjs/SqliteChangesetReader.js +11 -1
  30. package/lib/cjs/SqliteChangesetReader.js.map +1 -1
  31. package/lib/cjs/TxnManager.d.ts.map +1 -1
  32. package/lib/cjs/TxnManager.js +4 -0
  33. package/lib/cjs/TxnManager.js.map +1 -1
  34. package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts +90 -5
  35. package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
  36. package/lib/cjs/annotations/ElementDrivesTextAnnotation.js +59 -1
  37. package/lib/cjs/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  38. package/lib/cjs/internal/annotations/fieldSpecs.d.ts +82 -0
  39. package/lib/cjs/internal/annotations/fieldSpecs.d.ts.map +1 -0
  40. package/lib/cjs/internal/annotations/fieldSpecs.js +187 -0
  41. package/lib/cjs/internal/annotations/fieldSpecs.js.map +1 -0
  42. package/lib/cjs/internal/annotations/fields.d.ts +39 -2
  43. package/lib/cjs/internal/annotations/fields.d.ts.map +1 -1
  44. package/lib/cjs/internal/annotations/fields.js +140 -13
  45. package/lib/cjs/internal/annotations/fields.js.map +1 -1
  46. package/lib/esm/ChangesetReader.d.ts +1 -1
  47. package/lib/esm/ChangesetReader.js +2 -2
  48. package/lib/esm/ChangesetReader.js.map +1 -1
  49. package/lib/esm/ChangesetReaderTypes.d.ts +4 -1
  50. package/lib/esm/ChangesetReaderTypes.d.ts.map +1 -1
  51. package/lib/esm/ChangesetReaderTypes.js +3 -0
  52. package/lib/esm/ChangesetReaderTypes.js.map +1 -1
  53. package/lib/esm/ECDb.d.ts +63 -6
  54. package/lib/esm/ECDb.d.ts.map +1 -1
  55. package/lib/esm/ECDb.js +62 -6
  56. package/lib/esm/ECDb.js.map +1 -1
  57. package/lib/esm/ECSqlStatement.d.ts +2 -2
  58. package/lib/esm/ECSqlStatement.js +2 -2
  59. package/lib/esm/ECSqlStatement.js.map +1 -1
  60. package/lib/esm/Element.d.ts.map +1 -1
  61. package/lib/esm/Element.js +6 -3
  62. package/lib/esm/Element.js.map +1 -1
  63. package/lib/esm/IModelDb.d.ts +12 -10
  64. package/lib/esm/IModelDb.d.ts.map +1 -1
  65. package/lib/esm/IModelDb.js +26 -12
  66. package/lib/esm/IModelDb.js.map +1 -1
  67. package/lib/esm/SchemaSync.d.ts +2 -2
  68. package/lib/esm/SchemaSync.d.ts.map +1 -1
  69. package/lib/esm/SchemaSync.js +2 -2
  70. package/lib/esm/SchemaSync.js.map +1 -1
  71. package/lib/esm/SqliteChangesetReader.d.ts +16 -8
  72. package/lib/esm/SqliteChangesetReader.d.ts.map +1 -1
  73. package/lib/esm/SqliteChangesetReader.js +11 -1
  74. package/lib/esm/SqliteChangesetReader.js.map +1 -1
  75. package/lib/esm/TxnManager.d.ts.map +1 -1
  76. package/lib/esm/TxnManager.js +4 -0
  77. package/lib/esm/TxnManager.js.map +1 -1
  78. package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts +90 -5
  79. package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
  80. package/lib/esm/annotations/ElementDrivesTextAnnotation.js +60 -2
  81. package/lib/esm/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  82. package/lib/esm/internal/annotations/fieldSpecs.d.ts +82 -0
  83. package/lib/esm/internal/annotations/fieldSpecs.d.ts.map +1 -0
  84. package/lib/esm/internal/annotations/fieldSpecs.js +179 -0
  85. package/lib/esm/internal/annotations/fieldSpecs.js.map +1 -0
  86. package/lib/esm/internal/annotations/fields.d.ts +39 -2
  87. package/lib/esm/internal/annotations/fields.d.ts.map +1 -1
  88. package/lib/esm/internal/annotations/fields.js +140 -13
  89. package/lib/esm/internal/annotations/fields.js.map +1 -1
  90. package/lib/esm/test/AnnotationTestUtils.d.ts +9 -0
  91. package/lib/esm/test/AnnotationTestUtils.d.ts.map +1 -1
  92. package/lib/esm/test/AnnotationTestUtils.js +17 -0
  93. package/lib/esm/test/AnnotationTestUtils.js.map +1 -1
  94. package/lib/esm/test/annotations/FieldFormat.test.d.ts +2 -0
  95. package/lib/esm/test/annotations/FieldFormat.test.d.ts.map +1 -0
  96. package/lib/esm/test/annotations/FieldFormat.test.js +738 -0
  97. package/lib/esm/test/annotations/FieldFormat.test.js.map +1 -0
  98. package/lib/esm/test/annotations/FieldFormattingLifecycle.test.d.ts +2 -0
  99. package/lib/esm/test/annotations/FieldFormattingLifecycle.test.d.ts.map +1 -0
  100. package/lib/esm/test/annotations/FieldFormattingLifecycle.test.js +323 -0
  101. package/lib/esm/test/annotations/FieldFormattingLifecycle.test.js.map +1 -0
  102. package/lib/esm/test/annotations/FieldSpecs.test.d.ts +2 -0
  103. package/lib/esm/test/annotations/FieldSpecs.test.d.ts.map +1 -0
  104. package/lib/esm/test/annotations/FieldSpecs.test.js +54 -0
  105. package/lib/esm/test/annotations/FieldSpecs.test.js.map +1 -0
  106. package/lib/esm/test/annotations/Fields.test.js +221 -27
  107. package/lib/esm/test/annotations/Fields.test.js.map +1 -1
  108. package/lib/esm/test/ecdb/CSVImport.test.d.ts +2 -0
  109. package/lib/esm/test/ecdb/CSVImport.test.d.ts.map +1 -0
  110. package/lib/esm/test/ecdb/CSVImport.test.js +186 -0
  111. package/lib/esm/test/ecdb/CSVImport.test.js.map +1 -0
  112. package/lib/esm/test/ecdb/ConcurrentQuery.test.js +19 -2
  113. package/lib/esm/test/ecdb/ConcurrentQuery.test.js.map +1 -1
  114. package/lib/esm/test/ecdb/ECDb.test.js +207 -95
  115. package/lib/esm/test/ecdb/ECDb.test.js.map +1 -1
  116. package/lib/esm/test/ecdb/ECSqlAst.test.js +2 -2
  117. package/lib/esm/test/ecdb/ECSqlAst.test.js.map +1 -1
  118. package/lib/esm/test/ecdb/ECSqlQuery.test.js +17 -11
  119. package/lib/esm/test/ecdb/ECSqlQuery.test.js.map +1 -1
  120. package/lib/esm/test/ecdb/QueryReaders.test.js +105 -30
  121. package/lib/esm/test/ecdb/QueryReaders.test.js.map +1 -1
  122. package/lib/esm/test/ecsql/dataset/ECSqlDatasets.d.ts.map +1 -1
  123. package/lib/esm/test/ecsql/dataset/ECSqlDatasets.js +7 -0
  124. package/lib/esm/test/ecsql/dataset/ECSqlDatasets.js.map +1 -1
  125. package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js +86 -7
  126. package/lib/esm/test/ecsql/src/ECSqlTestRunner.test.js.map +1 -1
  127. package/lib/esm/test/hubaccess/CodeSwap.test.js +78 -0
  128. package/lib/esm/test/hubaccess/CodeSwap.test.js.map +1 -1
  129. package/lib/esm/test/imodel/IModelElements.test.js +5 -0
  130. package/lib/esm/test/imodel/IModelElements.test.js.map +1 -1
  131. package/lib/esm/test/standalone/ChangesetReader.test.js +116 -7
  132. package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
  133. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js +61 -0
  134. package/lib/esm/test/standalone/DgnDomainMergeConflict.test.js.map +1 -1
  135. package/lib/esm/test/standalone/SQLiteDb.test.d.ts.map +1 -1
  136. package/lib/esm/test/standalone/SQLiteDb.test.js +116 -0
  137. package/lib/esm/test/standalone/SQLiteDb.test.js.map +1 -1
  138. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js +2 -2
  139. package/lib/esm/test/standalone/SQliteChangesetReaderAndChangesetECAdaptor.test.js.map +1 -1
  140. package/package.json +16 -14
@@ -54,12 +54,12 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
54
54
  * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
55
55
  * See LICENSE.md in the project root for license terms and full copyright notice.
56
56
  *--------------------------------------------------------------------------------------------*/
57
- import { DbResult, Id64 } from "@itwin/core-bentley";
57
+ import { DbResult, Guid, Id64 } from "@itwin/core-bentley";
58
58
  import { Code, ColorDef, IModel, SubCategoryAppearance } from "@itwin/core-common";
59
59
  import { Arc3d, IModelJson, Point3d } from "@itwin/core-geometry";
60
60
  import { assert, expect } from "chai";
61
61
  import { DrawingCategory } from "../../Category";
62
- import { _nativeDb, BriefcaseDb, ChannelControl } from "../../core-backend";
62
+ import { _nativeDb, BriefcaseDb, ChannelControl, DrawingGraphic, ElementGroupsMembers, ElementOwnsChildElements, ExternalSourceAspect } from "../../core-backend";
63
63
  import { HubMock } from "../../internal/HubMock";
64
64
  import { ChangesetReader } from "../../ChangesetReader";
65
65
  import * as path from "node:path";
@@ -1854,7 +1854,7 @@ describe("ChangesetReader update-full", () => {
1854
1854
  const elemNew = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "New");
1855
1855
  expect(elemNew).to.exist;
1856
1856
  assert.equal(elemNew.ECInstanceId, fullElementId);
1857
- assert.equal(elemNew.ECClassId, "0x176");
1857
+ assert.equal(rwIModel.getClassNameFromId(elemNew.ECClassId), "TestDomain:Test2dElement");
1858
1858
  assert.equal(elemNew.StrProp, "updated");
1859
1859
  assert.equal(elemNew.IntProp, 99);
1860
1860
  assert.equal(elemNew.LongProp, 0);
@@ -1901,7 +1901,7 @@ describe("ChangesetReader update-full", () => {
1901
1901
  const elemOld = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "Old");
1902
1902
  expect(elemOld).to.exist;
1903
1903
  assert.equal(elemOld.ECInstanceId, fullElementId);
1904
- assert.equal(elemOld.ECClassId, "0x176");
1904
+ assert.equal(rwIModel.getClassNameFromId(elemOld.ECClassId), "TestDomain:Test2dElement");
1905
1905
  assert.equal(elemOld.StrProp, "hello");
1906
1906
  assert.equal(elemOld.IntProp, 42);
1907
1907
  assert.equal(elemOld.LongProp, 9007199254740991);
@@ -2042,7 +2042,7 @@ describe("ChangesetReader update-full", () => {
2042
2042
  const elemNew = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "New");
2043
2043
  expect(elemNew).to.exist;
2044
2044
  assert.equal(elemNew.ECInstanceId, fullElementId);
2045
- assert.equal(elemNew.ECClassId, "0x176");
2045
+ assert.equal(rwIModel.getClassNameFromId(elemNew.ECClassId), "TestDomain:Test2dElement");
2046
2046
  assert.isUndefined(elemNew.StrProp);
2047
2047
  assert.isUndefined(elemNew.Model);
2048
2048
  assert.isUndefined(elemNew.LastMod);
@@ -2061,7 +2061,7 @@ describe("ChangesetReader update-full", () => {
2061
2061
  const elemOld = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "Old");
2062
2062
  expect(elemOld).to.exist;
2063
2063
  assert.equal(elemOld.ECInstanceId, fullElementId);
2064
- assert.equal(elemOld.ECClassId, "0x176");
2064
+ assert.equal(rwIModel.getClassNameFromId(elemOld.ECClassId), "TestDomain:Test2dElement");
2065
2065
  assert.isUndefined(elemOld.StrProp);
2066
2066
  assert.isUndefined(elemOld.Model);
2067
2067
  assert.deepEqual(Object.keys(elemOld).sort(), ["ECInstanceId", "ECClassId", "$meta"].sort());
@@ -2153,7 +2153,7 @@ describe("ChangesetReader update-full", () => {
2153
2153
  "StructProp.Y", "StructProp.Z"].sort());
2154
2154
  const elemOld = instances.find((i) => i.ECInstanceId === fullElementId && i.$meta.stage === "Old");
2155
2155
  expect(elemOld).to.exist;
2156
- assert.equal(elemOld.ECClassId, "0x176");
2156
+ assert.equal(rwIModel.getClassNameFromId(elemOld.ECClassId), "TestDomain:Test2dElement");
2157
2157
  assert.equal(elemOld.StrProp, "hello");
2158
2158
  assert.include(String(elemOld.BinProp), "bytes");
2159
2159
  assert.deepEqual(elemOld.$meta.rowOptions, { abbreviateBlobs: true });
@@ -3736,6 +3736,115 @@ describe("ChangesetReader: behaviour in case imodel is not in sync with changese
3736
3736
  }
3737
3737
  });
3738
3738
  });
3739
+ describe("ChangesetReader: PropertyFilter.InstanceKeyAndIdentifiers", () => {
3740
+ let iModel;
3741
+ let txn;
3742
+ let modelId;
3743
+ let categoryId;
3744
+ before(async () => {
3745
+ HubMock.startup("ChangesetReaderIdentifiersTest", KnownTestLocations.outputDir);
3746
+ const accessToken = "super manager token";
3747
+ const iModelId = await HubMock.createNewIModel({ iTwinId: HubMock.iTwinId, iModelName: "identifiersTest", description: "InstanceKeyAndIdentifiers", accessToken });
3748
+ iModel = await HubWrappers.downloadAndOpenBriefcase({ iTwinId: HubMock.iTwinId, iModelId, accessToken });
3749
+ iModel.channels.addAllowedChannel(ChannelControl.sharedChannelName);
3750
+ txn = startTestTxn(iModel, "InstanceKeyAndIdentifiers setup");
3751
+ await iModel.locks.acquireLocks({ shared: IModel.dictionaryId });
3752
+ const codeProps = Code.createEmpty();
3753
+ codeProps.value = "DrawingModel";
3754
+ [, modelId] = IModelTestUtils.createAndInsertDrawingPartitionAndModel(txn, codeProps, true);
3755
+ categoryId = DrawingCategory.insert(txn, IModel.dictionaryId, "Category", new SubCategoryAppearance());
3756
+ txn.saveChanges("setup");
3757
+ await iModel.locks.acquireLocks({ shared: modelId });
3758
+ });
3759
+ after(() => {
3760
+ txn.end();
3761
+ iModel?.close();
3762
+ HubMock.shutdown();
3763
+ });
3764
+ const insertGraphic = (props) => {
3765
+ const elementProps = { classFullName: DrawingGraphic.classFullName, model: modelId, category: categoryId, code: Code.createEmpty(), ...props };
3766
+ return txn.insertElement(elementProps);
3767
+ };
3768
+ const lastTxnId = () => iModel.txns.getLastSavedTxnProps().id;
3769
+ // An aspect or relationship can have the same id as an element or model, so also match the table.
3770
+ const readIdentifiers = (txnId, instanceId, table) => readTxn(iModel, txnId, PropertyFilter.InstanceKeyAndIdentifiers, { classIdsToClassNames: true })
3771
+ .filter((i) => i.ECInstanceId === instanceId && i.$meta.tables.includes(table));
3772
+ it("reads a reparent after the element is deleted, without querying the iModel", () => {
3773
+ // iTwin/itwinjs-core#9738: the reparent records Parent.Id but not Parent.RelECClassId, which cannot be read back once the element is deleted.
3774
+ const [parentA, parentB] = [insertGraphic(), insertGraphic()];
3775
+ const childId = insertGraphic({ parent: new ElementOwnsChildElements(parentA) });
3776
+ txn.saveChanges("insert child");
3777
+ txn.updateElement({ ...iModel.elements.getElementProps(childId), parent: new ElementOwnsChildElements(parentB) });
3778
+ txn.saveChanges("reparent child");
3779
+ const reparentTxnId = lastTxnId();
3780
+ txn.deleteElement(childId);
3781
+ txn.saveChanges("delete child");
3782
+ const reparented = readIdentifiers(reparentTxnId, childId, "bis_Element");
3783
+ expect(reparented.map((i) => i.$meta.stage).sort()).to.deep.equal(["New", "Old"]);
3784
+ for (const instance of reparented)
3785
+ expect(Object.keys(instance).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId"]);
3786
+ });
3787
+ it("returns the owning Element of an aspect, plus ExternalSourceAspect identifiers when it is deleted", () => {
3788
+ const [ownerId, scopeId] = [insertGraphic(), insertGraphic()];
3789
+ const aspectId = txn.insertAspect({
3790
+ classFullName: ExternalSourceAspect.classFullName,
3791
+ element: { id: ownerId },
3792
+ scope: { id: scopeId },
3793
+ identifier: "source-id",
3794
+ kind: "Element",
3795
+ version: "1",
3796
+ });
3797
+ txn.saveChanges("insert aspect");
3798
+ const insertTxnId = lastTxnId();
3799
+ const versionUpdate = { ...iModel.elements.getAspect(aspectId).toJSON(), version: "2" };
3800
+ txn.updateAspect(versionUpdate);
3801
+ txn.saveChanges("update aspect version");
3802
+ const updateTxnId = lastTxnId();
3803
+ txn.deleteAspect(aspectId);
3804
+ txn.saveChanges("delete aspect");
3805
+ const deleteTxnId = lastTxnId();
3806
+ // Scope, Kind, and Identifier are returned only for deleted rows.
3807
+ const inserted = readIdentifiers(insertTxnId, aspectId, "bis_ElementMultiAspect");
3808
+ expect(inserted).to.have.lengthOf(1);
3809
+ expect(Object.keys(inserted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "Element"]);
3810
+ expect(inserted[0].Element).to.deep.equal({ Id: ownerId });
3811
+ // Version is not an identifier, and the update did not record Element.
3812
+ const updated = readIdentifiers(updateTxnId, aspectId, "bis_ElementMultiAspect");
3813
+ expect(updated).to.have.lengthOf(2);
3814
+ for (const instance of updated)
3815
+ expect(Object.keys(instance).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId"]);
3816
+ const deleted = readIdentifiers(deleteTxnId, aspectId, "bis_ElementMultiAspect");
3817
+ expect(deleted).to.have.lengthOf(1);
3818
+ expect(deleted[0].$meta.op).to.equal("Deleted");
3819
+ expect(Object.keys(deleted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "Element", "Identifier", "Kind", "Scope"]);
3820
+ expect(deleted[0]).to.deep.include({ ECClassId: "BisCore.ExternalSourceAspect", Element: { Id: ownerId }, Scope: { Id: scopeId }, Kind: "Element", Identifier: "source-id" });
3821
+ });
3822
+ it("returns FederationGuid for a deleted element", () => {
3823
+ const federationGuid = Guid.createValue();
3824
+ const elementId = insertGraphic({ federationGuid });
3825
+ txn.saveChanges("insert element");
3826
+ txn.deleteElement(elementId);
3827
+ txn.saveChanges("delete element");
3828
+ const deleted = readIdentifiers(lastTxnId(), elementId, "bis_Element");
3829
+ expect(deleted).to.have.lengthOf(1);
3830
+ expect(deleted[0].$meta.op).to.equal("Deleted");
3831
+ expect(Object.keys(deleted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "FederationGuid"]);
3832
+ expect(deleted[0]).to.deep.include({ ECClassId: "BisCore.DrawingGraphic", FederationGuid: federationGuid });
3833
+ });
3834
+ it("returns source and target ids for a deleted link-table relationship", () => {
3835
+ const [sourceId, targetId] = [insertGraphic(), insertGraphic()];
3836
+ const props = { classFullName: ElementGroupsMembers.classFullName, sourceId, targetId, memberPriority: 1 };
3837
+ const relationshipId = txn.insertRelationship(props);
3838
+ txn.saveChanges("insert relationship");
3839
+ txn.deleteRelationship({ ...props, id: relationshipId });
3840
+ txn.saveChanges("delete relationship");
3841
+ const deleted = readIdentifiers(lastTxnId(), relationshipId, "bis_ElementRefersToElements");
3842
+ expect(deleted).to.have.lengthOf(1);
3843
+ expect(deleted[0].$meta.op).to.equal("Deleted");
3844
+ expect(Object.keys(deleted[0]).sort()).to.deep.equal(["$meta", "ECClassId", "ECInstanceId", "SourceECInstanceId", "TargetECInstanceId"]);
3845
+ expect(deleted[0]).to.deep.include({ ECClassId: "BisCore.ElementGroupsMembers", SourceECInstanceId: sourceId, TargetECInstanceId: targetId });
3846
+ });
3847
+ });
3739
3848
  describe("ChangesetReader: overflow table graceful recovery when ExclusiveRootClassId is NULL", () => {
3740
3849
  let rwIModel;
3741
3850
  let rwIModelId;