Cascade Policy Tutorial
Cascading is used to customize how your ORM interacts based on the needs of your business requirements. Onyx provides several options on how to cascade your data. This tutorial demonstrates how to defer the cascading of relationship data using the cascade policy.
Cascade Policies
Onyx supports the following cascade policies:
Policy | Description |
---|---|
Save | Persist related entities upon invoking a save. This will leave the related entity alone when deleting. It will, however, remove the relationship reference without persisting the related entity. |
Delete | When deleting an entity, the related entities will be deleted. The expected behavior may differ when working with "to many" relationships compared to "to one" relationships. Cascade delete will only occur when deleting an entity, not when removing an entity from a relationship list. |
All | Includes both Save and Delete policies. |
DeferSave | This is currently unsupported for the cloud database version. |
None | When persisting entities, the relationships are ignored. |
Steps to Use Cascade Policy (Onyx Cloud Database)
1
Define the Entities Using JSON Schema
Use the provided JSON schema to define your entities with the appropriate cascade policies. Deploy your database using this schema.
1{
2 "tables": [
3 {
4 "name": "Movie",
5 "identifier": {
6 "name": "movieId",
7 "type": "Int",
8 "generator": "Sequence"
9 },
10 "partition": "",
11 "attributes": [
12 {
13 "name": "movieId",
14 "type": "Int",
15 "isNullable": false
16 },
17 {
18 "name": "title",
19 "type": "String",
20 "isNullable": true
21 }
22 ],
23 "relationships": [
24 {
25 "name": "actors",
26 "inverse": "movie",
27 "inverseClass": "Actor",
28 "type": "OneToMany",
29 "fetchPolicy": "None",
30 "cascadePolicy": "None"
31 }
32 ],
33 "indexes": [],
34 "expanded": false,
35 "isEditing": false
36 },
37 {
38 "name": "Actor",
39 "identifier": {
40 "name": "actorId",
41 "type": "Int",
42 "generator": "None"
43 },
44 "partition": "",
45 "attributes": [
46 {
47 "name": "actorId",
48 "type": "Int",
49 "isNullable": false
50 },
51 {
52 "name": "firstName",
53 "type": "String",
54 "isNullable": true
55 },
56 {
57 "name": "lastName",
58 "type": "String",
59 "isNullable": true
60 }
61 ],
62 "relationships": [
63 {
64 "name": "movie",
65 "inverse": "actors",
66 "inverseClass": "Movie",
67 "type": "ManyToOne",
68 "fetchPolicy": "None",
69 "cascadePolicy": "None"
70 }
71 ],
72 "indexes": [],
73 "expanded": false,
74 "isEditing": false
75 }
76 ],
77 "revisionDescription": "Schema for Cascade Policy example"
78}
- Ensure that the
cascadePolicy
is set to"None"
for theactors
relationship. - Validate your schema to ensure all entity definitions and relationships are correctly specified.
2
Create Test Data Including a Movie and Several Actors
Create instances of your entities and populate them with data.
1// Populate the movie data with actors
2const starWarsMovie = new Movie();
3starWarsMovie.title = "Star Wars, A New Hope";
4
5const actors = [];
6
7const markHamill = new Actor();
8markHamill.actorId = 1;
9markHamill.firstName = "Mark";
10markHamill.lastName = "Hamill";
11
12const carrieFisher = new Actor();
13carrieFisher.actorId = 2;
14carrieFisher.firstName = "Carrie";
15carrieFisher.lastName = "Fisher";
16
17actors.push(markHamill);
18actors.push(carrieFisher);
19
20// Save the movie and actors
21await db.save(markHamill);
22await db.save(carrieFisher);
23await db.save(starWarsMovie);
- When you save the
Movie
entity, the relationships are not persisted due to theNone
policy. - This approach improves performance when dealing with large datasets.
- Ensure all entities are saved before setting up relationships.
3
Verify the Actors Were Not Associated to the Movie
Retrieve the movie entity and check its relationships.
1// Verify that actors are not associated yet
2const starWarsAfterSave1 = await db.findById("Movie", starWarsMovie.movieId);
3await db.initialize(starWarsAfterSave1, "actors");
4if (starWarsAfterSave1?.actors?.length === 0) {
5 console.log("Actors have NOT been associated yet");
6}
- The
actors
relationship should initially have a count of 0.
4
Save Relationship Data for the Movie
Save the movie first since the cascade policy is None in order to associate the actors with the movie. The movie id must be assigned.
1let starWarsMovie = new Movie();
2starWarsMovie.title = "Star Wars, A New Hope";
3
4// In order for the relationship to persist correctly the move must be saved first
5starWarsMovie = await db.save(startWarsMovie);
6
7// The relationship is now persisted since starWarsMovie has been saved and has it's id assigned
8markHamill.movies = [starWarsMovie];
9await db.save(markHamill);
10
11carrieFisher.movies = [starWarsMovie];
12await db.save(carrieFisher);
- Pass a
Set
of actor identifiers to associate them with the movie. - This method efficiently batches the relationship associations.
5
Fetch the Entity and View Its Relationships
Retrieve the movie entity again and verify that the relationships have been established.
1// Fetch the entity and view its relationships
2const starWarsAfterSave1 = await db.findById("Movie", starWarsMovie.movieId, { fetch: ["actors"] });
3if (starWarsAfterSave1?.actors?.length === 2) {
4 console.log("Actors have been associated!");
5}
- The movie should now have 2 actors associated with it.
Important Notes
- The
None
cascade policy is useful when batch insertion of entities is required, improving performance by deferring relationship persistence. - When using cascade policy
None
, ensure all related entities are saved beforehand.
Troubleshooting
- Relationships Not Persisting: Ensure that relationship entities have their identifiers set when the cascade policy is set to
None
. - Incorrect Cascade Policy: Verify that the cascade policy is set to
DeferSave
where appropriate.
Next Steps
Now that you understand how to use the cascade policy, you can explore related topics: