2013-12-21 13 views
12

Ich brauche auf einmal tief ein Objekt auf den Server zu speichern und nicht in der Lage gewesen, alle Beispiele online zu finden, die die neuesten ember Daten (1.0.0-beta.4) verwenden.Ember Daten: Speicher von Beziehungen

Zum Beispiel mit diesen Modellen: (jsfiddle)

App.Child = DS.Model.extend({ 
    name: DS.attr('string'), 
    age: DS.attr('number'), 
    toys: DS.hasMany('toy', {async:true, embedded:'always'}), 
}); 
App.Toy = DS.Model.extend({ 
    name: DS.attr('string'), 
    child: DS.belongsTo('child') 
}); 

Und dieser Code:

actions: { 
    save: function(){ 
     var store = this.get('store'), 
      child, toy; 

     child = store.createRecord('child', { 
      name: 'Herbert' 
     }); 
     toy = store.createRecord('toy', { 
      name: 'Kazoo' 
     }); 

     child.set('toys', [toy]); 
     child.save(); 
    } 
} 

Es speichert nur die JSON für das Objekt Kind aber keine des Spielzeugs - nicht einmal Seite geladen:

{ 
    child: { 
    age: null 
    name: "Herbert" 
    } 
} 

Muss ich die Spielzeuge manuell speichern t oo? Gibt es trotzdem, dass ich es kann die folgende JSON an den Server senden:

{ 
    child: { 
    age: null 
    name: "Herbert", 
    toys: [{ 
     name: "Kazoo" 
    }] 
    } 
} 

Oder

{ 
    child: { 
    age: null 
    name: "Herbert", 
    toys: [1] 
    } 
} 

See JSFiddle: http://jsfiddle.net/jgillick/LNXyp/2/

Antwort

0

ich ein tiefes Objekt erforderlich sein, statt eine Seite geladen ein, so basiert auf kingpin2k Antwort, ich kam mit dieser:

DS.JSONSerializer.reopen({ 
    serializeHasMany: function(record, json, relationship) { 
     var key = relationship.key, 
      property = Ember.get(record, key), 
      relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship); 

     if (property && relationshipType === 'manyToNone' || relationshipType === 'manyToMany' || 
      relationshipType === 'manyToOne') { 

      // Add each serialized nested object 
      json[key] = []; 
      property.forEach(function(item, index){ 
       json[key].push(item.serialize()); 
      }); 
     } 
    } 
}); 

wenn Sie jetzt child.serialize() nennen, wird es dieses Objekt zurückgeben:

{ 
    child: { 
    name: "Herbert", 
    toys: [ 
     { 
     name: 'Kazoo' 
     } 
    ] 
    } 
} 

Welche ist das, was ich brauche. Hier ist die jsfiddle mit ihm in Aktion: http://jsfiddle.net/jgillick/LNXyp/8/

+0

Mit Ember 1.3.1/data 1.0.0-beta 6 scheint 'property = Ember.get (record, key)' ein leeres Array zu ergeben. Das ist besonders merkwürdig, weil ich mit 'record.get ('key') und dann (function (items) {...}) 'auf die untergeordneten Datensätze zugreifen kann. Irgendeine Idee, wenn das ein bekanntes Problem ist? – eriknelson

3

Spielzeug nicht beide async und eingebettet immer sein kann, das sind widersprüchliche Optionen. Embedded ist derzeit nur auf dem aktiven Modell-Serializer vorhanden.

toys: DS.hasMany('toy', {embedded:'always'}) 

das Spielzeug ist eine ManyToOne Beziehung, und da die Beziehung auf der belongsTo Seite existiert, ist es effizienter, die Beziehung während des Spielzeugs zu retten ist speichern. Davon abgesehen, wenn Sie es auf einmal erstellen, wollen sie dann in einem großen Teil speichern, das ist, wo überwiegende ins Spiel kommt.

serializeHasMany: function(record, json, relationship) { 
    var key = relationship.key; 

    var relationshipType = DS.RelationshipChange.determineRelationshipType(record.constructor, relationship); 

    if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany' || 
     relationshipType === 'manyToOne') { 
    json[key] = get(record, key).mapBy('id'); 
    // TODO support for polymorphic manyToNone and manyToMany relationships 
    } 
}, 

Und Ihre speichern sollte wie dieses

var store = this.get('store'), 
     child, toy; 

    child = store.createRecord('child', { 
     name: 'Herbert' 
    }); 
    toy = store.createRecord('toy', { 
     name: 'Kazoo' 
    }); 

    child.get('toys').pushObject(toy); 
    child.save().then(function(){ 
     toy.save(); 
    }, 
    function(err){ 
     alert('error', err); 
    }); 
+0

Wo ist 'Spielzeug' definiert? In der Zeile, in der du anrufst: 'toys.save()' Und wenn du 'child.get ('toys'). Save()' meinst, oder um auf die Antwort des Versprechens zuzugreifen, ruft dieser Aufruf jedes auf der gleichgültigen Modelle oder rette sie alle auf einmal? Ich habe das gleiche Problem wie Jeremy und wenn ich versuche, die hasMany -Eigenschaft zu debuggen/inspizieren, wie in diesem Fall child.get ('Spielzeuge') schauen, gerade nachdem ich dort einen neuen Datensatz geschoben, die Werte im Array sind null. Ich nahm an, dass dies daran lag, dass Ember-Data weiß, dass die ID des Spielzeugs in der Spielwarenkombination gespeichert werden muss, aber das Spielzeug hat noch keine ID, weil es nicht gespeichert wurde. –

+0

Ja, das sollte "Spielzeug" sein, ich rettete das einzelne Spielzeug. – Kingpin2k

+0

Also wenn ich das richtig verstehe. Wir haben Modelle mit einer Eins-zu-Viele-Beziehung eingerichtet, Kind hat viele Spielzeuge und Spielzeug gehört zu Kind. Intern wird es eine 'childId'-Eigenschaft auf dem Spielzeugmodell geben, die tatsächlich beibehalten wird. Wenn Sie 'child.pushObject (toy)' aufrufen, wird die Beziehung zwischen den beiden hergestellt und sobald Kind gespeichert ist, wird die childId -Eigenschaft des Spielzeugs automatisch aktualisiert. Ich hatte erwartet, dass Sie 'toy.set ('child', response)' innerhalb des Verspre- chen-Vervollständigungshandlers aufrufen müssen. –

8

Die Antworten sind nicht mehr aktuell. Ember Daten unterstützt nun eingebettete Datensätze, die Sie genau das tun können, was Sie suchen zu tun, das ist die vollständige Objektgraph in einer großen Nutzlast zu erhalten und zu senden. Zum Beispiel werden, wenn Ihre Modelle wie folgt aufgebaut:

App.Child = DS.Model.extend({ 
    name: DS.attr('string'), 
    age: DS.attr('number'), 
    toys: DS.hasMany('toy') 
}); 
App.Toy = DS.Model.extend({ 
    name: DS.attr('string'), 
    child: DS.belongsTo('child') 
}); 

Sie können eine benutzerdefinierte Serializer für Ihr Kind Modell definieren:

App.ChildSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { 
    attrs: { 
    toys: {embedded: 'always'} 
    } 
}); 

Dies sagt Ember Daten, die Sie anderen zeigen möchten ‚Spielzeug‘ zu als Teil der "Kind" -Nutzlast enthalten sein.Ihre HTTP-GET-Antwort von Ihrer API sollte wie folgt aussehen:

{ 
    "child": { 
    "id": 1, 
    "name": "Todd Smith", 
    "age": 5, 
    "toys": [ 
     {"id": 1, "name": "boat"}, 
     {"id": 2, "name": "truck"} 
    ] 
    } 
} 

Und wenn Sie Ihr Modell speichern, werden Ember Daten diese an den Server senden:

{ 
    "child":{ 
     "name":"Todd Smith", 
     "age":5, 
     "toys":[ 
     { 
      "id":"1", 
      "name":"boat", 
      "child":"1" 
     }, 
     { 
      "id":"2", 
      "name":"truck", 
      "child":"1" 
     } 
     ] 
    } 
} 

hier ein JSBin ist, das dies demonstriert.

http://emberjs.jsbin.com/cufaxe/3/edit?html,js,output

Im JSbin, wenn Sie die Schaltfläche ‚Speichern‘ klicken, werden Sie den Dev-Inspektor verwenden müssen, um die Anforderung zu sehen, die an den Server gesendet wird.

+0

Wissen Sie, ob dies die bevorzugte Methode ist? Mein Verständnis ist, dass eingebettete Datensätze in Ihren GET-Antworten nicht immer am effizientesten sind. Ich kann jedoch die Vorteile der Einbettung von Datensätzen bei POST/PUT-Anfragen sehen. – antony

+1

@antony, Sie fragen nach einer API-Designfrage, die sich nicht speziell mit Ember Data befasst. Wenn Sie an Aggregate glauben (z. B. Auftrag hat Auftragspositionen, aber Auftragspositionen allein keine Identität), sollten Sie eingebettete Datensätze verwenden. Wenn Sie außerdem Aktualisierungen in einer atomaren Transaktion benötigen (z. B. Reihenfolge und Reihenfolge der Elemente), sollten Sie eingebettete Datensätze verwenden. Wenn jedoch jedes Modell seinen eigenen identifizierbaren Endpunkt haben kann, sind eingebettete Datensätze nicht sinnvoll. –

Verwandte Themen