Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember - Understanding Inverse Relationships

Tags:

ember.js

After reading through the Getting Started guide on Ember's page, I'm still a bit confused what exactly an inverse relationship is, and when to define them. I understand that you will probably need to use them when defining multiple relationships of the same type, but I found the example to be very unclear. This is the sample from the docs:

var belongsTo = DS.belongsTo,     hasMany = DS.hasMany;  App.Comment = DS.Model.extend({   onePost: belongsTo('post'),   twoPost: belongsTo('post'),   redPost: belongsTo('post'),   bluePost: belongsTo('post') });   App.Post = DS.Model.extend({   comments: hasMany('comment', {     inverse: 'redPost'   }) }); 

In this example, why is the redPost singled out as the inverse instead of one of the other kinds of posts? How does defining redPost as the inverse differentiate it from the rest? I also don't really understand why a comment has multiple posts at all really, just adding to my confusion.

like image 517
ncksllvn Avatar asked Sep 05 '14 20:09

ncksllvn


1 Answers

First of all, this post might explain things a bit. It's not your exact question, but the reasons for the answer are similar.

But, to get a clear understanding of what inverses are, you should be familiar with directed graphs. While not immediately apparent, directed graphs are what fuel the idea behind belongsTo and hasMany.

But let's get back to specifics. Let's take their example, only eliminate some stuff to make it more realistic.

App.Post = DS.Model.extend({     comments: DS.hasMany('comment', { inverse: 'post' }) });  App.Comment = DS.Model.extend({     post: DS.belongsTo('post', { inverse: 'comments' }) }); 

This is a more real world example. Each post can have any number of comments, while a comment must belong to exactly one post. Makes sense. As you can see, those inverses refer to each other. But what is an inverse? An inverse relationship just describes what the edge between two nodes is called on the other side. For example, look at this picture:

enter image description here

You'll see two nodes with a single edge between them. From the perspective of a Post object, the edge is called comments. If you wanted get the node connected by that edge, you could call post.get('comments'). But from the perspective of the Comment object, the edge is called post. If you wanted to get the node connected by that edge using the Comment object, you'd have to call comment.get('post'). That's what an inverse is. It describes how different objects refer to the same relationship. Different name, same edge. By explicitly declaring the inverse, you tell one object what the other object calls the edge.

Why is that important? Well, Ember-Data needs to know that so it can reciprocate relationships. For example, let's say you have the following code:

var post = store.find('post', '1'); var newComment = store.createRecord('comment', {});  ...  post.get('comments').addObject(newComment); 

What you did is create a new comment and connect it to an existing post object. A simple enough use case. But there's one problem: you only told the post about the comment, not vice-versa. You told the post that you connected the comment, but you didn't tell the comment that you connected it to the post. But as a user, you expect those both to happen at the same time. Well, they do, and that's because Ember-Data does it for you. Using the names of the inverse relationship, Ember-Data ensures that when you do one, the other happens as well. When you do this:

post.get('comments').addObject(newComment); 

Ember-Data, behind the scenes, really does this:

post.get('comments').addObject(newComment); newComment.set('post', post); 

That is why Ember-Data needs the inverse relationship: so it can maintain integrity without you having to worry about it.

like image 172
GJK Avatar answered Oct 05 '22 10:10

GJK