You can give the objects in a package a durable GUID, creation and change timestamps, and a deletion record by making a shared superclass the package's default superclass; this is for modelers building integrations, APIs, imports, exports, or long-lived links.
Why object identity hygiene matters
An object needs an identity that remains meaningful when data moves between systems. A database row ID is local to one database instance, so it is not suitable as an identifier in an API payload, an import/export file, or a link saved outside that instance. Use a GUID for that purpose.
A GUID (Globally Unique Identifier) distinguishes objects created independently in different systems. For example, two systems can each create a user with the same name and local row ID, while their GUIDs still distinguish the two users.
Creation and change timestamps help another system discover new and changed reference data asynchronously. A deletion log addresses the other half of synchronization: when an object disappears in the producing system, the importing system needs a record of that deletion to remove or mark its local copy.
Create a superclass that provides the common data and lifecycle methods. Then make it the default superclass for the package so that classes in the package inherit this behavior.
The superclass needs these attributes:
| Attribute | Purpose | Example value |
|---|---|---|
Guid
|
A durable identity for use outside the local database. | 30dd879c-ee2f-11db-8314-0800200c9a66
|
CreateTime
|
The time at which the object was created. | The time a new Customer is created. |
ChangeTime
|
The time of the latest saved update. | The time a Customer's address is changed and saved. |
Also create a deletion-log class named DeletedObj with a DeletedGuid attribute. Each deletion creates one instance of this class and retains the deleted object's GUID. An integration can then transfer these deletion records alongside new and changed objects.
Configure the default superclass
- Select the package that contains the classes to which you want to apply the behavior.
- Set the shared superclass as the package's Default superclass.
- Confirm that the classes in the package inherit the superclass attributes and methods.
- Add the lifecycle methods described below to the superclass.
For example, if Customer belongs to the package, creating a Customer creates its inherited Guid and CreateTime. Updating the Customer sets its inherited ChangeTime. Deleting it creates a DeletedObj that contains the Customer GUID.
Add lifecycle methods
MDriven triggers a method named OnCreate, OnUpdate, or OnDelete when that method is found on a class for the corresponding create, update, or delete event.
Set creation time and GUID
Add an OnCreate method to the superclass. Use this OCL body:
CreateTime:=DateTime.Now;
self.Guid.newGuid()This records the current time and generates the GUID when an object is created.
Set change time
Add an OnUpdate method to the superclass. Use this OCL body:
self.ChangeTime:=DateTime.NowAfter a new object has been saved, it receives a ChangeTime. Later updates refresh this value.
Record deletions
Add an OnDelete method to the superclass. Use this OCL body:
let x=DeletedObj.Create in(
x.DeletedGuid:=self.Guid
)When an object is deleted, this creates a deletion-log object and copies the deleted object's GUID to DeletedGuid. Do not depend on the deleted object itself being available to an importing system; transfer the deletion record instead.
Choose the right identifier
| Identifier | Use it for | Do not use it for |
|---|---|---|
| GUID | Object identity across database instances, APIs, transferred data, and long-lived exposed links. | Database primary and foreign-key relationships inside one database. |
| ExternalId | Resolving an object in MDriven when the class discriminator and object identity are available. ExternalIds can use a class name, and can also use a Guid property in the <classid>!GP!<guid> form.
|
A permanent, model-independent public identifier when its class-index form may change after a model update. |
| Local integer row ID | Efficient primary-key and foreign-key relationships within the same database. | Data interchange, APIs, or object identification outside that database instance. |
Do not include a GUID in a database index. GUIDs are unique and are not efficient index values for this purpose. Keep integer keys internal to the database, and use the GUID when data crosses a system boundary.
Use GUIDs in exposed links
If you expose an object identity in a saved link, a QR code, or an API value, prefer a GUID-based ExternalId over the numeric class-index form. A numeric class ID can change when the model changes. A GUID-based form is more stable over time.
For example, an image request can identify an object and its Blob attribute with a GUID-based ExternalId:
http://localhost:5052/Turnkey/GetImage?img=Thing!GP!ad833fd8383c4389a88f3349166e7a74-SomeImage
The GP segment means Guid Property. MDriven can resolve an ExternalId using a property named Guid, typed as Guid or string; see objectfromExternalId. For Blob download and access considerations, see Documentation:MVC GetImage.
An identifier that is hard to guess is not an authorization mechanism. Protect access with the relevant ViewModel access controls and security design; see Training:Security.
Operational checks
Before relying on this pattern in an integration, verify the following:
- A newly created object has both
CreateTimeandGuid. - Saving the object sets
ChangeTime. - Deleting the object creates a
DeletedObjrecord with the expectedDeletedGuid. - Export and API code identifies objects by GUID rather than by a local integer row ID.
- Consumers process deletion records as well as created and changed records.
