Fetch Policy Tutorial
The Fetch Policy can be used to optimize your object graph. Onyx enables developers to load only what they need. There are instances when users would like to reduce the size of the object graph in order to save memory and network overhead by lazily or not loading relationships.
Policy | Description |
---|---|
Eager | Eager fetch policy will hydrate the entire relationship and all of the subsequent object graph. |
Lazy | Lazy fetch policy will return references to the relationship data. When referenced using the List interface, the relationship will be lazily filled in. |
None | The relationship will not be populated upon fetching an entity. It will sometimes be populated in the event the entity is already cached. |
Steps to Use Fetch Policy (Onyx Cloud Database)
1
Declare the Entities Using JSON Schema
Use the provided JSON schema to define your entities and relationships. Deploy your database using this schema definition.
1{
2 "tables": [
3 {
4 "name": "Series",
5 "identifier": {
6 "name": "seriesId",
7 "type": "String",
8 "generator": "None"
9 },
10 "attributes": [
11 {
12 "name": "seriesId",
13 "type": "String",
14 "isNullable": false
15 }
16 ],
17 "relationships": [
18 {
19 "name": "seasons",
20 "inverse": "series",
21 "inverseClass": "Season",
22 "type": "OneToMany",
23 "fetchPolicy": "Eager",
24 "cascadePolicy": "All"
25 }
26 ]
27 },
28 {
29 "name": "Season",
30 "identifier": {
31 "name": "seasonId",
32 "type": "Long",
33 "generator": "Sequence"
34 },
35 "attributes": [
36 {
37 "name": "seasonId",
38 "type": "Long",
39 "isNullable": false
40 },
41 {
42 "name": "seasonNumber",
43 "type": "Int",
44 "isNullable": false
45 },
46 {
47 "name": "seasonYear",
48 "type": "Int",
49 "isNullable": false
50 }
51 ],
52 "relationships": [
53 {
54 "name": "series",
55 "inverse": "seasons",
56 "inverseClass": "Series",
57 "type": "ManyToOne",
58 "fetchPolicy": "None",
59 "cascadePolicy": "None"
60 },
61 {
62 "name": "episodes",
63 "inverse": "season",
64 "inverseClass": "Episode",
65 "type": "OneToMany",
66 "fetchPolicy": "Lazy",
67 "cascadePolicy": "Save"
68 }
69 ]
70 },
71 {
72 "name": "Episode",
73 "identifier": {
74 "name": "episodeId",
75 "type": "String",
76 "generator": "None"
77 },
78 "attributes": [
79 {
80 "name": "episodeId",
81 "type": "String",
82 "isNullable": false
83 },
84 {
85 "name": "episodeNumber",
86 "type": "Int",
87 "isNullable": false
88 }
89 ],
90 "relationships": [
91 {
92 "name": "season",
93 "inverse": "episodes",
94 "inverseClass": "Season",
95 "type": "ManyToOne",
96 "fetchPolicy": "None",
97 "cascadePolicy": "None"
98 }
99 ]
100 },
101 {
102 "name": "Actor",
103 "identifier": {
104 "name": "actorId",
105 "type": "Int",
106 "generator": "Sequence"
107 },
108 "attributes": [
109 {
110 "name": "actorId",
111 "type": "Int",
112 "isNullable": false
113 },
114 {
115 "name": "firstName",
116 "type": "String",
117 "isNullable": true
118 },
119 {
120 "name": "lastName",
121 "type": "String",
122 "isNullable": true
123 }
124 ],
125 "relationships": []
126 }
127 ],
128 "revisionDescription": "Schema for Fetch Policy tutorial"
129}
- Ensure that relationship types and inverse properties are correctly specified.
- Set the appropriate
fetchPolicy
for each relationship to control how data is loaded.
2
Populate Test Data
Create instances of your entities and populate your object graph. Use the
save
function to persist the entire graph.1// Populate some test data
2const theSopranos = {
3 seriesId: "SOPRANOS",
4 seasons: []
5};
6
7const firstSeason = {
8 seasonNumber: 1,
9 seasonYear: 1999,
10 episodes: []
11};
12
13const secondSeason = {
14 seasonNumber: 2,
15 seasonYear: 2000,
16 episodes: []
17};
18
19const thirdSeason = {
20 seasonNumber: 3,
21 seasonYear: 2001,
22 episodes: []
23};
24
25const fourthSeason = {
26 seasonNumber: 4,
27 seasonYear: 2002,
28 episodes: []
29};
30
31// Add the seasons to the sopranos
32theSopranos.seasons = [firstSeason, secondSeason, thirdSeason, fourthSeason];
33
34firstSeason.episodes = [
35 { episodeId: "s01e01", episodeNumber: 1, actors: [] },
36 { episodeId: "s01e02", episodeNumber: 2, actors: [] },
37 { episodeId: "s01e03", episodeNumber: 3, actors: [] },
38 { episodeId: "s01e04", episodeNumber: 4, actors: [] },
39 { episodeId: "s01e05", episodeNumber: 5, actors: [] }
40];
41
42secondSeason.episodes = [
43 { episodeId: "s02e01", episodeNumber: 6, actors: [] },
44 { episodeId: "s02e02", episodeNumber: 7, actors: [] },
45 { episodeId: "s02e03", episodeNumber: 8, actors: [] },
46 { episodeId: "s02e04", episodeNumber: 9, actors: [] },
47 { episodeId: "s02e05", episodeNumber: 10, actors: [] }
48];
49
50// ...
51
52const james = {
53 firstName: "James",
54 lastName: "Gandolfini"
55};
56
57const steve = {
58 firstName: "Steve",
59 lastName: "Buscemi"
60};
61
62theSopranos.seasons.forEach(season => {
63 season.episodes.forEach(episode => {
64 episode.actors = [james, steve];
65 });
66});
67
68// Save the Series. Note: This will persist the entire object graph
69await db.save(Series, theSopranos);
- Relationships with cascade policies of
CascadePolicy.SAVE
orCascadePolicy.ALL
will ensure related entities are persisted.
3
Fetch and Verify Eager Relationships
Retrieve a fresh copy of the
Series
entity to demonstrate how eager relationships are loaded.1// Fetch a new copy of the entity to illustrate how eager relationships are fetched
2const theSopranosCopy = await db.findById(Series, theSopranos.seriesId);
3
4console.assert(theSopranosCopy.seasons != null, "Seasons should be populated because it is eagerly fetched");
5console.assert(Array.isArray(theSopranosCopy.seasons), "Seasons should be fully populated as an Array");
- Verify that the
seasons
relationship is populated and fully loaded.
4
Verify Lazy Loading of Relationships
Access the
episodes
relationship of a Season
to demonstrate lazy loading.1// Verify that episodes are lazily loaded
2const firstSeasonCopy = theSopranosCopy.seasons[0];
3console.assert(firstSeasonCopy.episodes != null, "The first season's episodes should not be null since it is lazily loaded");
4console.assert(firstSeasonCopy.episodes instanceof LazyRelationshipCollection, "The first season's episodes should be LazyRelationshipCollection");
5
6// When we reference an episode, it gets hydrated
7const episode = firstSeasonCopy.episodes[0];
- The
episodes
relationship should be lazily loaded and hydrated upon access. - Relationships with
FetchPolicy.NONE
may need explicit initialization.
Important Notes
- Choosing the correct fetch policy is crucial for optimizing performance and memory usage.
- Use
FetchPolicy.EAGER
when you need the full object graph immediately. - Use
FetchPolicy.LAZY
to defer loading until the relationship is accessed. - Use
FetchPolicy.NONE
when you do not need the relationship data or want to manually control loading.
Troubleshooting
- Unexpected Null Relationships: Verify that your fetch policies are set correctly and that related entities are properly persisted.
- Performance Issues: Use lazy or none fetch policies to reduce memory footprint and improve performance.
- Data Not Loading: For relationships with
FetchPolicy.NONE
, use explicit initialization if needed.
Next Steps
Now that you understand how to use fetch policies to optimize your object graph, you can explore more advanced topics: