ExtJS and Complex Save Operations
ExtJS 4.1.0
Update 6/6/13 :
I have posted this same question on the Sencha forums where there hasn't been much action. The post is more or less the same, but I figured I would add it here just for reference. I am still eager to hear other community members' input on what must be a very common scenario in an ExtJS Application! http://www.sencha.com/forum/showthread.php?265358-Complex-Model-Save-Decoupling-Data-and-Updating-Related-Stores
Update 7/16/13 (Conclusion?)
The Sencha post garnered very little discussion. I have decided to put the majority of the load of complex save operations on my application server and lazily refresh client stores where need be. This way I can use my own Database wrapper to encompass all of the transactions associated with one complex Domain Object save to guarantee atomicity. If saving a new Order
consists of saving the order metadata, ten new instances of OrderContents
and potentially other information (addresses residing in other tables, a new customer defined at the time of order creation, etc.) I would much rather send the payload to the application server, rather than establish a vulgar web of callbacks in client-side application code. Data which is associated on a One-to-One basis (such as an Order
hasOne Address
) is updated in the success
callback of the Order.save()
operation. More complex data, such as the Order
's contents, is lazily handled by simply calling contentStore.sync()
. I feel that this is the means to guarantee atomicity without an overwhelming number of client-callbacks
Original Post Content
Given the overall disappointing functionality of saving association-heavy models, I have all but ditched model associations in my application and rely retrieving associated data myself. This is all well and good, but unfortunately does not resolve the issue of actually saving the data and updating ExtJS stores to reflect the changes on the server.
Take for example saving an Order
object, which is composed of metadata as well as OrderContents
ie, the parts on the order. The metadata ends up in an Order_Data
table in the database, whereas the contents all end up in an Order_Contents
table where each row is linked to the parent order via an order_id
column.
On the client, retrieving the contents for an order is quite easy to do without any need for associations: var contents = this.getContentsStore().query('order_id', 10).getRange()
. However, a major flaw is that this is hinging on the content records being available in the OrderContents
ExtJS Store , which would apply if I were using associations NOT returned by the data server with the "main" object.
When saving an order, I send a single request which holds the order's metadata (eg, date, order number, supplier information, etc.) as well as an array of contents. These pieces of data are picked apart and saved to their appropriate tables. This makes enough sense to me and works well.
All is well until it comes to returning saved/updated records from the application server. Since the request is fired off by calling a OrderObject.save()
, there is nothing telling the OrderContents
store that new records are available. This would be handled automatically if I were to instead add records to the store and call .sync()
, but I feel this complicates the saving process and I would just much rather handle this decoupling on the application server not to mention, saving an entire request is quite nice as well.
Is there a better way to solve this? My current solution is as follows...
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
}
});
By calling commitChanges()
the records added to the store are considered to be clean (non-phantom, non-dirty) and thus are no longer returned by the store's getModifiedRecords()
method; rightly so as the records should not be passed to the application server in the event of a store.sync()
.
This approach just seems kinda sloppy/hacky to me but I haven't figured out a better solution...
Any input / thoughts are greatly appreciated!
Update 8/26/13 I found that associated data is indeed handled by Ext in the create/update callback on the model's proxy, but finding that data wasn't easy... See my post here: ExtJS 4.1 - Returning Associated Data in Model.Save() Response
Well, it's been a couple months of having this question open and I feel like there is no magically awesome solution to this problem.
My solution is as follows...
When saving a complex model (eg, a model that would, or does have a few hasMany
associations), I save the 'parent' model which includes all associated data (as a property/field on the model!) and then add the (saved) associated data in the afterSave/afterUpdate callback.
Take for example my PurchaseOrder
model which hasMany
Items
and hasOne
Address
. Take note that the associated data is included in the model's properties, as it will not be passed to the server if it solely exists in the model's association store.
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
I have Models
established for PurchaseOrder.Content
and PurchaseOrder.Address
, yet the data in the PurchaseOrder
is not an instance of these models, rather just the data. Again, this is to ensure that it is passed correctly to the application server.
Once I have an object like described above, I send it off to my application server via .save()
as follows:
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;
}
}
My application server receives the PurchaseOrder
and handles saving the data accordingly. I will not go into gross details as this process is largely dependent on your own implementation. My application framework is loosely based on Zend 1.11 (primarily leveraging Zend_Db
).
I feel this is the best approach for the following reasons:
success
method of the callback can simply reload
stores. I will let this answer sit for a bit to encourage discussion.
Thanks for reading!
链接地址: http://www.djcxy.com/p/76384.html上一篇: ExtJS 4 MVC视图和子/子控制器困难的多个实例
下一篇: ExtJS和复杂的保存操作