Many-to-Many Relationship Tutorial
The many-to-many relationship is used for defining associations where multiple instances of one entity are associated with multiple instances of another entity. This tutorial demonstrates how to define and use a many-to-many relationship within Onyx Database.
Steps to Define a Many-to-Many Relationship (Onyx Cloud Database)
1
Declare the Entities
Use the provided JSON schema to declare your entities with many-to-many relationships and deploy the database using this schema definition.
1{
2 "tables": [
3 {
4 "name": "Movie",
5 "identifier": {
6 "name": "movieId",
7 "type": "Long",
8 "generator": "Sequence"
9 },
10 "attributes": [
11 {
12 "name": "movieId",
13 "type": "Long"
14 },
15 {
16 "name": "title",
17 "type": "String"
18 }
19 ],
20 "relationships": [
21 {
22 "name": "actors",
23 "inverse": "movies",
24 "inverseClass": "Actor",
25 "type": "ManyToMany",
26 "fetchPolicy": "Lazy",
27 "cascadePolicy": "Save"
28 }
29 ]
30 },
31 {
32 "name": "Actor",
33 "identifier": {
34 "name": "actorId",
35 "type": "Long",
36 "generator": "Sequence"
37 },
38 "attributes": [
39 {
40 "name": "actorId",
41 "type": "Long"
42 },
43 {
44 "name": "actorFirstName",
45 "type": "String"
46 },
47 {
48 "name": "actorLastName",
49 "type": "String"
50 }
51 ],
52 "relationships": [
53 {
54 "name": "movies",
55 "inverse": "actors",
56 "inverseClass": "Movie",
57 "type": "ManyToMany",
58 "fetchPolicy": "Lazy",
59 "cascadePolicy": "None"
60 }
61 ]
62 }
63 ],
64 "revisionDescription": "Initial schema for many-to-many relationship example"
65}
- Ensure that each table and attribute name follows valid conventions and that relationships are correctly specified.
- Relationships must have valid names and specify both an
inverse
property andinverseClass
that refer to the corresponding related table and attribute. - Many-to-many relationships must be reciprocally defined in both entities.
- Cascade and fetch policies should be explicitly defined using supported values.
2
Create the Entities and Define Their Relationships
Create instances of your entities and establish their relationships.
1// Define Harrison Ford Actor
2const harrisonFordActor = new Actor();
3harrisonFordActor.actorFirstName = "Harrison";
4harrisonFordActor.actorLastName = "Ford";
5
6// Define Mark Hamill Actor
7const markHamillActor = new Actor();
8markHamillActor.actorFirstName = "Mark";
9markHamillActor.actorLastName = "Hamill";
10
11// Create Star Wars Movie
12const starWarsMovie = new Movie();
13starWarsMovie.title = "A New Hope";
14
15// Create Indiana Jones Movie
16const indianaJonesMovie = new Movie();
17indianaJonesMovie.title = "Raiders of the Lost Ark";
18
19// Set relationship for Star Wars Movie to its actors
20starWarsMovie.actors = [harrisonFordActor, markHamillActor];
21
22// Set relationship for Indiana Jones Movie to its actors
23indianaJonesMovie.actors = [harrisonFordActor];
24
25// Optional. You do not need to set the inverse relationships
26/*
27harrisonFordActor.movies = [starWarsMovie, indianaJonesMovie];
28markHamillActor.movies = [starWarsMovie];
29*/
30
31// Persist the movies
32await db.save(starWarsMovie);
33await db.save(indianaJonesMovie);
- Assign the related entities to establish the many-to-many relationships.
- You can optionally set the inverse relationships; however, Onyx will infer these during persistence.
3
Persist the Entities
Use the Persistence Manager to save your entities.
1// Define Harrison Ford Actor
2const harrisonFordActor = new Actor();
3harrisonFordActor.actorFirstName = "Harrison";
4harrisonFordActor.actorLastName = "Ford";
5
6// Define Mark Hamill Actor
7const markHamillActor = new Actor();
8markHamillActor.actorFirstName = "Mark";
9markHamillActor.actorLastName = "Hamill";
10
11// Create Star Wars Movie
12const starWarsMovie = new Movie();
13starWarsMovie.title = "A New Hope";
14
15// Create Indiana Jones Movie
16const indianaJonesMovie = new Movie();
17indianaJonesMovie.title = "Raiders of the Lost Ark";
18
19// Set relationship for Star Wars Movie to its actors
20starWarsMovie.actors = [harrisonFordActor, markHamillActor];
21
22// Set relationship for Indiana Jones Movie to its actors
23indianaJonesMovie.actors = [harrisonFordActor];
24
25// Optional. You do not need to set the inverse relationships
26/*
27harrisonFordActor.movies = [starWarsMovie, indianaJonesMovie];
28markHamillActor.movies = [starWarsMovie];
29*/
30
31// Persist the movies
32await db.save(starWarsMovie);
33await db.save(indianaJonesMovie);
- The related entities will be automatically persisted due to the
cascadePolicy
.
4
Find and Hydrate the Actor Entity
Retrieve the actor entity and initialize its lazy-loaded relationships.
1// Fetch Harrison Ford Actor
2harrisonFordActor = await db.findById(Actor, harrisonFordActor.actorId);
3console.log(`Harrison Ford has been in ${harrisonFordActor.movies.length} movies including ${harrisonFordActor.movies[0].title} and ${harrisonFordActor.movies[1].title}!`);
- Use
initialize
to hydrate a lazy relationship, such as"movies"
. - Verify that the actor entity has been hydrated, and the movies have been associated correctly.
Important Notes
- Onyx does not differentiate between a parent or a child entity; the cascade policy determines the behavior during persistence.
- Defining inverse relationship values is optional; Onyx will infer relationships based on your entity definitions.
- 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: Verify that all relationships specify a valid
inverseClass
andinverse
, and that the inverse relationship exists in the related table. - Relationship Type Mismatch: Ensure that paired relationships use compatible types (e.g.,
ManyToMany
withManyToMany
). - 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 many-to-many relationship, you can explore more advanced topics: