Updating an Entity's Relationship Within Your Model

This tutorial demonstrates how to update relationships within your data model in Onyx Database. You will learn how to modify relationship cardinality, such as changing a OneToOne relationship to a OneToMany, and observe how the database handles these updates.

Steps to Update Your Model (Onyx Cloud Database)

1

Declare the Entities Using JSON Schema

Use the provided JSON schema to declare your Payment and Invoice entities. This schema defines the initial relationships and attributes for your entities.
1{
2  "tables": [
3    {
4      "name": "Invoice",
5      "identifier": {
6        "name": "invoiceId",
7        "type": "Long",
8        "generator": "None"
9      },
10      "attributes": [
11        {
12          "name": "invoiceId",
13          "type": "Long"
14        },
15        {
16          "name": "invoiceDate",
17          "type": "Date"
18        },
19        {
20          "name": "dueDate",
21          "type": "Date"
22        },
23        {
24          "name": "amount",
25          "type": "Double"
26        },
27        {
28          "name": "notes",
29          "type": "String"
30        }
31      ],
32      "relationships": [
33        {
34          "name": "payments",
35          "inverse": "invoice",
36          "inverseClass": "Payment",
37          "type": "OneToOne",
38          "cascadePolicy": "Save",
39          "fetchPolicy": "Eager"
40        },
41        {
42          "name": "account",
43          "inverse": "invoices",
44          "inverseClass": "Account",
45          "type": "ManyToOne"
46        }
47      ]
48    },
49    {
50      "name": "Payment",
51      "identifier": {
52        "name": "paymentId",
53        "type": "Long",
54        "generator": "None"
55      },
56      "attributes": [
57        {
58          "name": "paymentId",
59          "type": "Long"
60        },
61        {
62          "name": "amount",
63          "type": "Double"
64        },
65        {
66          "name": "notes",
67          "type": "String"
68        }
69      ],
70      "relationships": [
71        {
72          "name": "invoice",
73          "inverse": "payments",
74          "inverseClass": "Invoice",
75          "type": "OneToOne"
76        }
77      ]
78    }
79  ],
80  "revisionDescription": "Initial schema for updating entity relationships"
81}
  • Ensure your schema defines all required attributes, including types and relationships.
  • The identifier field is mandatory for each table and must include a unique name and a supported generator type.
  • Relationships must have a valid name and specify both an inverse property and inverseClass that refer to the corresponding related table and attribute.
2

Modify the Invoice and Payment Entities to Change Relationship Cardinality

Update the JSON schema to change the relationship from a OneToOne to a ManyToOne and from OneToOne to OneToMany. This modification allows multiple payments to be associated with a single invoice.
1{
2  "tables": [
3    {
4      "name": "Invoice",
5      "identifier": {
6        "name": "invoiceId",
7        "type": "Long",
8        "generator": "None"
9      },
10      "attributes": [
11        {
12          "name": "invoiceId",
13          "type": "Long"
14        },
15        {
16          "name": "invoiceDate",
17          "type": "Date"
18        },
19        {
20          "name": "dueDate",
21          "type": "Date"
22        },
23        {
24          "name": "amount",
25          "type": "Double"
26        },
27        {
28          "name": "notes",
29          "type": "String"
30        }
31      ],
32      "relationships": [
33        {
34          "name": "payments",
35          "inverse": "invoice",
36          "inverseClass": "Payment",
37          "type": "ManyToOne",
38          "cascadePolicy": "Save",
39          "fetchPolicy": "Eager"
40        },
41        {
42          "name": "account",
43          "inverse": "invoices",
44          "inverseClass": "Account",
45          "type": "ManyToOne"
46        }
47      ]
48    },
49    {
50      "name": "Payment",
51      "identifier": {
52        "name": "paymentId",
53        "type": "Long",
54        "generator": "None"
55      },
56      "attributes": [
57        {
58          "name": "paymentId",
59          "type": "Long"
60        },
61        {
62          "name": "amount",
63          "type": "Double"
64        },
65        {
66          "name": "notes",
67          "type": "String"
68        }
69      ],
70      "relationships": [
71        {
72          "name": "invoice",
73          "inverse": "payments",
74          "inverseClass": "Invoice",
75          "type": "ManyToOne"
76        }
77      ]
78    }
79  ],
80  "revisionDescription": "Modified relationships for Invoice and Payment entities"
81}
  • Changing the relationship type from OneToOne to ManyToOne for Invoice to Payment.
  • Updating the inverse relationship from OneToOne to OneToMany for Payment to Invoice.
  • Ensure that all other properties such as fetchPolicy and cascadePolicy are correctly updated as needed.
3

Verify Updated Relationship

Verify that the relationship update has been applied correctly by retrieving the Invoice and checking the associated Payment entities.
1// Verify Updated Relationship
2const myLatestInvoice = await db.findById('Invoice', 1);
3
4// This used to be a single entity and now it is a list of payments since the relationship has changed from OneToOne to ManyToOne
5const paymentList = myLatestInvoice.payments;
6
7// What previously was a one to one relationship should have the existing record in the set.
8console.assert(paymentList.length === 1);
9console.assert(paymentList[0].paymentId === 1);
10
11// Let's add another payment to ensure we can have a ToMany Relationship
12const mySecondPayment = {
13    amount: 10.01,
14    notes: "Getting a start on next month's bill since I don't have enough money because I am too busy writing open source software and not focusing on my day job.",
15    invoice: myLatestInvoice
16};
17
18// Persist the Payment
19await db.save('Payment', mySecondPayment);
20
21// Refresh the collection and ensure there are 2 items
22await db.initialize(myLatestInvoice, 'payments');
23
24console.assert(paymentList.length === 2);
  • After updating the schema, use the provided Kotlin code to verify the relationships.
  • Ensure that multiple payments can be associated with a single invoice.

Important Notes

  • Changing relationship types is supported if the original type can be converted to the new type. Ensure that the new relationship type aligns with your data integrity requirements.
  • Modifying relationships does not delete existing data. The data remains accessible through the updated relationships.
  • When updating relationships, ensure that both sides of the relationship are consistently updated to maintain referential integrity.

Troubleshooting

  • Type Conversion Errors: Ensure that the original relationship type can be converted to the new type without data loss. For example, converting from OneToOne to ManyToOne is generally safe, but always verify with your specific data model.
  • Data Not Reflecting Changes: After modifying the model, ensure that you redeploy the schema (for Cloud) or reinitialize the database connection (for Open Source) and reload any entities to reflect the changes.
  • Missing Data After Removing Relationships: Remember that modifying relationships does not delete the associated data. Ensure that you manage orphaned data appropriately if needed.

Next Steps

Now that you have learned how to update relationships within your model, you can explore more advanced topics: