2013-05-14 9 views
10

ExtJS 4.1.0ExtJS und Komplexe speichern Operationen

-Update 6/6/13:

ich diese gleiche Frage auf den Sencha Foren gepostet haben, wo es nicht viel Aktion war. Der Beitrag ist mehr oder weniger der gleiche, aber ich dachte, ich würde es hier nur als Referenz hinzufügen. Ich bin immer noch gespannt auf die Beiträge anderer Community-Mitglieder zu einem sehr häufigen Szenario in einer ExtJS-Anwendung! http://www.sencha.com/forum/showthread.php?265358-Complex-Model-Save-Decoupling-Data-and-Updating-Related-Stores

-Update 7/16/13 (Schlussfolgerung?)

Die Sencha Post sammelte sehr wenig Diskussion. Ich habe mich entschieden, den Großteil der Last von komplexen Speicheroperationen auf meinen Anwendungsserver zu legen und Clientspeicher dort, wo es nötig ist, langsam zu aktualisieren. Auf diese Weise kann ich meinen eigenen Datenbank-Wrapper verwenden, um alle Transaktionen abzubilden, die mit einem komplexen Domänenobjekt-Speicher verknüpft sind, um die Atomarität zu gewährleisten. Wenn ein neues Order gespeichert wird, besteht darin, die Metadaten der Bestellung zu speichern, zehn neue Instanzen von OrderContents und möglicherweise weitere Informationen (Adressen in anderen Tabellen, ein neuer Kunde zum Zeitpunkt der Auftragserstellung usw.) den Anwendungsserver, anstatt ein vulgäres Netz von Rückrufen im clientseitigen Anwendungscode einzurichten. Daten, die auf einer Eins-zu-eins-Basis zugeordnet sind (z. B. Order hasOne Address), werden im success-Rückruf der Order.save()-Operation aktualisiert. Komplexere Daten, wie der Inhalt der Order, werden einfach durch den Aufruf contentStore.sync() behandelt. Ich glaube, dass dies das Mittel ist Unteilbarkeit ohne eine überwältigende Anzahl von Client-Rückrufe

Original-Beitrag Inhalt

In Anbetracht der insgesamt enttäuschenden Funktionalität des Sparens vereins schweren Modelle zu gewährleisten, habe ich alle aber ditched Modellverknüpfungen in meiner Anwendung und verlassen sich darauf, zugehörige Daten selbst abzurufen. Das ist alles gut und gut, aber leider löst nicht das Problem der tatsächlichen Speicherung der Daten und der Aktualisierung von ExtJS-Speichern, um die Änderungen auf dem Server widerzuspiegeln.

Nehmen Sie zum Beispiel ein Order Objekt speichern, das aus Metadaten sowie OrderContents, d. H. Die Teile auf der Bestellung besteht. Die Metadaten landen in einer Order_Data Tabelle in der Datenbank, während die Inhalte alle in einer Order_Contents Tabelle enden, in der jede Zeile über eine order_id Spalte mit der übergeordneten Reihenfolge verknüpft ist.

Auf dem Client ist das Abrufen der Inhalte für eine Bestellung relativ einfach, ohne dass Assoziationen erforderlich sind: var contents = this.getContentsStore().query('order_id', 10).getRange(). Ein großer Fehler ist jedoch, dass dies auf die Content-Datensätze in der OrderContents ExtJS Store hingehen, die gelten würde, wenn ich Verknüpfungen verwenden würde NICHT vom Datenserver mit dem "Haupt" -Objekt zurückgegeben.

Beim Speichern einer Bestellung sende ich eine einzelne Anfrage, die die Metadaten der Bestellung (z. B. Datum, Bestellnummer, Lieferanteninformationen usw.) sowie eine Reihe von Inhalten enthält. Diese Daten werden ausgewählt und in den entsprechenden Tabellen gespeichert. Das macht mir genug Sinn und funktioniert gut.

Alles ist gut, bis die gespeicherten/aktualisierten Datensätze vom Anwendungsserver zurückgegeben werden.Da die Anforderung abgefeuert wird, indem ein OrderObject.save() aufgerufen wird, gibt es nichts, das dem OrderContents Speicher mitteilt, dass neue Datensätze verfügbar sind. Dies würde automatisch erledigt werden, wenn ich stattdessen Datensätze zum Laden hinzufügen und .sync() aufrufen würde, aber ich fühle, dass dies den Speichervorgang erschwert und ich würde lieber diese Entkopplung auf dem Anwendungsserver behandeln, ganz zu schweigen von dem Speichern einer gesamten Anforderung auch nett.

Gibt es einen besseren Weg, dies zu lösen? Meine aktuelle Lösung ist wie folgt ...

var orderContentsStore = this.getOrderContentsStore(); 
MyOrderObject.save({ 
    success: function(rec, op){ 
     // New Content Records need to be added to the contents store! 
     orderContentsStore.add(rec.get('contents')); // Array of OrderContent Records 
     orderContentsStore.commitChanges(); // This is very important 
    } 
}); 

Durch den Aufruf commitChanges() die in den Laden hinzugefügten Datensätze berücksichtigt werden sauber (nicht-Phantom, nicht schmutzig) sein und somit nicht zurück mehr durch den getModifiedRecords() Methode des Speichers ; zu Recht, da die Datensätze im Falle einer store.sync() nicht an den Anwendungsserver übergeben werden sollten.

Dieser Ansatz scheint nur ein bisschen schlampig/Hacky mir, aber ich habe nicht eine bessere Lösung ...

sind Jede Eingabe/Gedanken heraus sehr zu schätzen!

+1

Leider ist dies der einzige Weg, es zu tun. Alternativ könnten Sie Ihren eigenen "Schreiber" auf dem Proxy des Ladens schreiben und die verschiedenen Modelle dort handhaben, aber das wäre auch unordentlich. – Mike

+0

Danke für die Bestätigung meiner Überzeugungen @Mike. Ich werde eines Tages einen Blogpost schreiben und diese Frage mit Informationen aus dem Beitrag beantworten. Ich habe erwogen, eine verrückte Erweiterung für den Data Writer zu implementieren, aber für das, was es erreichen würde (Speichern einer store.load() hier und da), würde ich die zusätzliche Komplexität und Zeit, die für die Implementierung erforderlich ist, nicht wert sein. –

Antwort

3

-Update 8/26/13 ich, dass zugehörige Daten gefunden in der Tat von Extern in dem Update-Rückruf auf das Modell der Proxy erstellen/gehandhabt werden, aber diese Daten zu finden, waren nicht einfach ... Siehe meinen Beitrag hier: ExtJS 4.1 - Returning Associated Data in Model.Save() Response

Nun, es ist ein paar Monate, diese Frage offen zu haben, und ich habe das Gefühl, dass es keine magisch großartige Lösung für dieses Problem gibt.

Meine Lösung ist wie folgt ...

Wenn ein komplexes Modell speichern (zB ein Modell, das würde, oder ein paar hasMany Verbände hat) und ich spare den ‚Eltern‘ Modell, das alle zugehörigen Daten enthält (als Eigenschaft/Feld im Modell!) und fügen Sie dann die (gespeicherten) zugehörigen Daten in den afterSave/afterUpdate-Callback ein.

Nehmen Sie zum Beispiel mein PurchaseOrder Modell, das hasManyItems und hasOneAddress. Beachten Sie, dass die zugehörigen Daten in den Eigenschaften des Modells enthalten sind, da sie nicht an den Server übergeben werden, wenn sie nur im Zuordnungsspeicher des Modells vorhanden sind.

console.log(PurchaseOrder.getData()); 
--- 
id: 0 
order_num: "PO12345" 
order_total: 100.95 
customer_id: 1 
order_address: Object 
    id: 0 
    ship_address_1: "123 Awesome Street" 
    ship_address_2: "Suite B" 
    ship_city: "Gnarlyville" 
    ship_state: "Vermont" 
    ship_zip: "05401" 
    ...etc... 
contents: Array[2] 
    0: Object 
     id: 0 
     sku: "BR10831" 
     name: "Super Cool Shiny Thing" 
     quantity: 5 
     sold_price: 84.23 
    1: Object 
     id: 0 
     sku: "BR10311" 
     name: "Moderately Fun Paddle Ball" 
     quantity: 1 
     sold_price: 1.39 

Ich habe Models für PurchaseOrder.Content etabliert und PurchaseOrder.Address, noch die Daten in den PurchaseOrder keine Instanz dieser Modelle, sondern nur die Daten. Auch dies stellt sicher, dass es korrekt an den Anwendungsserver übergeben wird.

Einmal habe ich ein Objekt wie oben beschrieben, ich habe es über .save() meiner Anwendungsserver abzuschicken wie folgt:

PurchaseOrder.save({ 
    scope: me, 
    success: me.afterOrderSave, 
    failure: function(rec,op){ 
     console.error('Error saving Purchase Order', op); 
    } 
}); 

afterOrderSave: function(record, operation){ 
    var me = this; 
    switch(operation.action){ 
     case 'create': 
      /** 
       * Add the records to the appropriate stores. 
       * Since these records (from the server) have an id, 
       * they will not be marked as dirty nor as phantoms 
       */ 
      var savedRecord = operation.getResultSet().records[0]; // has associated! 
      me.getOrderStore().add(savedRecord); 
      me.getOrderContentStore().add(savedRecord.getContents()); //association! 
      me.getOrderAddressStore().add(savedRecord.getAddress()); // association! 
      break; 

     case 'update': 
      // Locate and update records with response from server 
      break; 
    } 
} 

Mein Anwendungsserver die PurchaseOrder erhält und verarbeitet die Daten entsprechend zu speichern. Ich werde nicht in grobe Details gehen, da dieser Prozess weitgehend von Ihrer eigenen Implementierung abhängt. Mein Anwendungsframework basiert lose auf Zend 1.11 (hauptsächlich die Verwendung von Zend_Db).

Ich empfinde dies der beste Ansatz für die folgenden Gründe:

  • Keine unordentliche Reihe von verschiedenen Modellen.save() Rückrufe auf dem Client
  • nur eine Anfrage, die sehr einfach
  • Atomicity verwalten leicht auf dem Anwendungsserver behandelt werden
  • weniger Umläufe = weniger potenzielle Fehlerquellen zu befürchten
  • Wenn Sie sind wirklich faul, die success Methode des Rückrufs kann einfach reload speichert.

Ich lasse diese Antwort ein wenig sitzen, um die Diskussion zu fördern.

Danke fürs Lesen!

+0

Ich denke, es ist wahrscheinlich einer der saubersten Wege zu gehen. +1 – Mike

+0

@Mike Danke für das Follow-up, schätze es! –