lundi 16 novembre 2015

How do I update a bidirectional relationship when using a primitive backend (e. g. gist or localStorage)?

I'm building an Ember that works with a primitive backend, e. g. gist.github.com or localStorage. The backend is unable to do any relationship synchronization.

But Ember Data does synchronize relationships bidirectionally and it turns out to be a source of problems.

Imagine that I've got a Child record that belongs to Parent1. The relationship is bidirectional and is already persisted on the backend:

Ember

Child               Parent1               Parent2
---------------     -----------------     ------------
parent: Parent1     children: [Child]     children: []



Storage

Child               Parent1               Parent2
---------------     -----------------     ------------
parent: Parent1     children: [Child]     children: []

Now I update the Child to belong to Parent2. When I do that, Ember will update Parent1 to not have the Child, and Parent2 to have the Child:

Ember

Child               Parent1               Parent2
---------------     -----------------     ------------
parent: Parent2     children: []          children: [Child]



Storage

Child               Parent1               Parent2
---------------     -----------------     ------------
parent: Parent1     children: [Child]     children: []

Now I save the Child to the primitive backend:

Ember

Child               Parent1               Parent2
---------------     -----------------     ------------
parent: Parent2     children: []          children: [Child]
           ↓
           ↓
           ↓
Storage    ↓
           ↓
Child      ↓        Parent1               Parent2
---------------     -----------------     ------------
parent: Parent2     children: [Child]     children: []

If only the Child is updated, then the backend will remember the Child belonging to Parent2, but Parent2 will not reference Child, and Parent1 will still reference Child.

The backend is in an inconsistent state. If I refresh the app, it's a matter of chance whether the Child will appear belonging to Parent1, Parent2 or no parent at all. The outcome seems to depend on the order the records come from the backend and are parsed by Ember Data:

Ember

Child               Parent1               Parent2
---------------     -----------------     -------------
parent:    ?        children:   [?]       children: [?]
           ↑                     ↑                   ↑
           ↑                     ↑                   ↑
           ↑                     ↑                   ↑
Storage    ↑                     ↑                   ↑
           ↑                     ↑                   ↑
Child      ↑        Parent1      ↑        Parent2    ↑
---------------     -----------------     -------------
parent: Parent2     children: [Child]     children:  []

Thus, in order to update Child's bidirectional relationship, I need to submit Parent1 and Parent2 to the backend alongside Child.

But Parent1 and Parent2 might be dirty, and I don't want to persist the parents' state because the uses does not expect that. So I need to submit parents in their initial state, with only the the relationship to Child updated.

My head goes round already, but that's not all. Ember Data does not track the clean/dirty state of relationships, so it's impossible to know which relationships to update, and I see no other way than to save them all.

The questions are:

  1. Where do I handle this? Adapter? Serializer? Model? Store? The Ember Data pipeline is way too complicated and hard to grasp.
  2. When saving a record, how do I access related records?
  3. How do I take a snapshot of initial state of a related record?
  4. Am I missing something?

PS ember-localstorage-adapter suffers from the described problem, which results in relationships breaking. http://ift.tt/1lrd1la




Aucun commentaire:

Enregistrer un commentaire