One-to-Many Relationship Tutorial
The one-to-many relationship is a powerful methodology for associating multiple child entities to a parent. Onyx Database allows features such as lazy loading and customized transactions. This tutorial demonstrates how to define and use a one-to-many relationship within Onyx Database.
Steps to Define a One-to-Many Relationship (Onyx Cloud Database)
1
Declare the Entities
Use the provided JSON schema to declare your entities with one-to-many relationships and deploy the database using this schema definition.
1{
2 "tables": [
3 {
4 "name": "Sailboat",
5 "identifier": {
6 "name": "registrationCode",
7 "type": "String",
8 "generator": "None"
9 },
10 "partition": "",
11 "attributes": [
12 {
13 "name": "registrationCode",
14 "type": "String"
15 },
16 {
17 "name": "name",
18 "type": "String"
19 }
20 ],
21 "relationships": [
22 {
23 "name": "crew",
24 "inverse": "sailboat",
25 "inverseClass": "CrewMember",
26 "type": "OneToMany",
27 "fetchPolicy": "Lazy",
28 "cascadePolicy": "All"
29 }
30 ],
31 "indexes": [],
32 "expanded": false,
33 "isEditing": false
34 },
35 {
36 "name": "CrewMember",
37 "identifier": {
38 "name": "id",
39 "type": "Long",
40 "generator": "Sequence"
41 },
42 "partition": "",
43 "attributes": [
44 {
45 "name": "id",
46 "type": "Long"
47 },
48 {
49 "name": "firstName",
50 "type": "String"
51 },
52 {
53 "name": "lastName",
54 "type": "String"
55 }
56 ],
57 "relationships": [
58 {
59 "name": "sailboat",
60 "inverse": "crew",
61 "inverseClass": "Sailboat",
62 "type": "ManyToOne",
63 "fetchPolicy": "None",
64 "cascadePolicy": "None"
65 }
66 ],
67 "indexes": [],
68 "expanded": false,
69 "isEditing": false
70 }
71 ],
72 "revisionDescription": "Initial schema for one-to-many relationship example"
73}
- Table names and attributes must follow valid Kotlin variable name conventions.
- Each table must have a unique name and at least one attribute defined.
- The
identifier
attribute for a table must exist in the attributes list and match its type requirements. - Relationships must have a valid name and specify both an
inverse
property andinverseClass
that refer to the corresponding related table and attribute. - To-one relationships (e.g.,
OneToOne
,ManyToOne
) must have a corresponding inverse relationship defined in the related table. - Relationship types must align with the expected pairing (e.g.,
OneToMany
should matchManyToOne
). - Cascade and fetch policies must be explicitly defined and must use supported values.
2
Create the Entities and Their Relationship
Instantiate a sailboat and create several crew members. Add the crew members to the sailboat's crew list to establish the relationship.
1// Create a sailboat named Stars and Stripes
2const sailboat = new Sailboat();
3sailboat.registrationCode = "USA11";
4sailboat.name = "Stars and Stripes";
5
6// Create the list of crew members
7const crew = [];
8
9const skipper = new CrewMember();
10skipper.firstName = "Dennis";
11skipper.lastName = "Connor";
12
13const tactician = new CrewMember();
14tactician.firstName = "Ben";
15tactician.lastName = "Ainslie";
16
17crew.push(skipper);
18crew.push(tactician);
19
20// Associate the crew members to the sailboat
21sailboat.crew = crew;
- Assign the list of crew members to the sailboat to establish the one-to-many relationship.
3
Persist the Sailboat Entity
Use the Persistence Manager to save your entity.
1await db.save(sailboat);
2console.log(`Sailboat ${sailboat.name} has ${sailboat.crew.length} crew members`);
- The related entities will be automatically persisted due to the
cascadePolicy
.
4
Fetch the Sailboat Entity
Retrieve the saved entity to confirm it has been persisted correctly.
1const savedSailboat = await db.findById("USA11");
2console.log(`Sailboat has ${savedSailboat?.crew?.length} crew members`);
3console.log(`${savedSailboat?.crew?.[0]?.firstName} is the skipper on boat ${savedSailboat?.crew?.[0]?.sailboat?.name}`);
- Verify that the crew members are properly loaded and associated with the sailboat.
Important Notes
- The
cascadePolicy
determines how related entities are persisted or deleted when performing operations on the parent entity. - The
fetchPolicy
influences how related entities are loaded, which can impact performance. - Ensure that the relationship annotations are correctly specified to prevent runtime errors.
Troubleshooting
- Missing or Invalid Inverse: Check that table inverse names match the related table's attribute name and that the inverse class is correctly specified.
- Duplicate Names: Ensure that table names, attribute names, and relationship names are unique within the schema.
- Relationship Configuration Errors: Ensure all relationships specify a valid
inverseClass
andinverse
, and that the inverse relationship exists in the related table. - Relationship Type Mismatch: Verify that paired relationships use compatible types (e.g.,
OneToMany
withManyToOne
). - Invalid Cascade or Fetch Policy: Check that the cascade and fetch policies are explicitly defined and use valid values such as
None
,All
, orLazy
. - Schema Validation Errors: Use the provided error messages during validation to locate and fix issues such as missing attributes, invalid types, or misconfigured relationships.
Next Steps
Now that you have learned how to define a one-to-many relationship, you can explore more advanced relationship types: