ExtJS和复杂保存操作 [英] ExtJS and Complex Save Operations

查看:211
本文介绍了ExtJS和复杂保存操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ExtJS 4.1.0



更新6/6/13



我在Sencha论坛上发布了同样的问题,那里没有太多的动作。这个帖子或多或少是一样的,但我想我会把它添加在这里供参考。我仍然渴望听到其他社区成员对ExtJS应用程序中常见的情况的投入!
http:// www.sencha.com/forum/showthread.php?265358-Complex-Model-Save-Decoupling-Data-and-Updating-Related-Stores



更新7/16/13(结论?)



Sencha帖子获得了很少的讨论。我决定将大部分复杂的保存操作加载到我的应用服务器上,并在需要的时候懒洋洋地刷新客户端存储。这样我可以使用我自己的数据库包装器来包含与一个复杂的域对象关联的所有事务保存以保证原子性。如果保存新的订单包括保存订单元数据,可以使用 OrderContents 的十个新实例和潜在的其他信息(驻留的地址在其他表格中,订单创建时定义的新客户等)我宁愿将有效负载发送到应用程序服务器,而不是在客户端应用程序代码中建立一个粗俗的回调网络。以一对一为基础的数据(例如订单 hasOne 地址)在成功回调 Order.save()操作。通过简单地调用 contentStore.sync()来简单地处理更复杂的数据,例如 Order 的内容。 我觉得这是保证原子性的手段,而没有压倒多数的客户端回调



原始帖子内容



鉴于存储关联重型模型的整体令人失望的功能,我在应用程序中除了丢弃了模型关联,并且依赖于自己检索关联数据。这很好,但不幸的是不能解决实际保存数据和更新ExtJS商店以反映服务器上的更改的问题。



以保存为例一个订单对象,它由元数据以及 OrderContents 即订单上的部分组成。元数据最终位于数据库中的 Order_Data 表中,而所有内容最终都位于 Order_Contents 表中,其中每个行通过 order_id 列链接到父级订单。



在客户端上,检索订单的内容很容易做,而不需要关联: var contents = this.getContentsStore()。query('order_id',10).getRange()。然而,一个主要的缺陷就在于,这取决于 OrderContents ExtJS Store 中可用的内容记录,如果我使用关联数据服务器返回的不是main对象。



当保存订单时,我发送一个包含订单元数据的单个请求(例如日期,订单号,供应商信息等)以及一系列内容。将这些数据片段分开并保存到其适当的表格中。这对我来说足够有意义,并且效果很好。



直到从应用程序服务器返回保存/更新的记录为止。由于通过调用 OrderObject.save()触发了请求,所以没有什么可以告诉 OrderContents 存储新的记录可用。如果我要将记录添加到商店并调用 .sync(),那么这将自动处理,但是我觉得这样会使得保存过程复杂化,我只会处理在应用程序服务器上的这种解耦更不用说,保存整个请求也是非常好的。



有更好的解决方法吗?我目前的解决方案如下...

  var orderContentsStore = this.getOrderContentsStore(); 
MyOrderObject.save({
success:function(rec,op){
//新内容记录需要添加到内容存储!
orderContentsStore.add(rec。 get('contents')); // OrderContent记录数组
orderContentsStore.commitChanges(); //这非常重要
}
});

通过调用 commitChanges()添加的记录商店被认为是干净的(非幻影,非肮脏),因此不再由商店的 getModifiedRecords()方法返回;正确地,如果在$ code> store.sync()的情况下不应将记录传递到应用程序服务器。



这个方法对我来说似乎有点马虎虎虎,但是我并没有想出更好的解决方案。



任何输入/想法都非常感谢! p>

解决方案

更新8/26/13 我发现相关数据确实由Ext在创建/更新模型代理的回调,但发现数据不容易...请参阅我的帖子: ExtJS 4.1 - 在Model.Save()响应中返回关联数据



嗯,这是几个月有这个问题开放,我觉得这个问题没有什么神奇的解决方案。



我的解决方案如下...



保存一个复杂的模型(例如,一个模型,或者确实有几个 hasMany 关联),我保存包含所有关联数据的父模型(作为模型上的属性/字段!),然后添加(保存)相关联的数据在afterSave / afterUpdate回调。



以例如$ PurchaseOrder $ c> hasMany 项目 hasOne 地址。请注意,相关数据包含在模型的属性中,因为它不会传递到服务器,如果它仅存在于模型的关联商店中。

 的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:套房B
ship_city:Gnarlyville
ship_state:Vermont
ship_zip:05401
...等...
内容:数组[2]
0:对象
id:0
sku:BR10831
name:超酷闪亮的东西
数量:5
sold_price:84.23
1:对象
id:0
sku:BR10311
名称:中等有趣的桨球
数量:1
sold_price:1.39

code>为 PurchaseOrder.Content PurchaseOrder.Address 建立的模型 PurchaseOrder 中的数据不是这些模型的实例,而是数据。再次,这是为了确保它被正确地传递给应用程序服务器。



一旦我有一个如上所述的对象,我将它发送到我的应用程序服务器通过 .save()如下:

  PurchaseOrder.save({
范围:我,
成功:me.afterOrderSave,
失败:function(rec,op){
console.error('Save saving Order',op);
}
});

afterOrderSave:function(record,operation){
var me = this;
switch(operation.action){
case'create':
/ **
*将记录添加到相应的商店。
*由于这些记录(从服务器)有一个id,
*它们不会被标记为脏,也不会被标记为幻影
* /
var savedRecord = operation.getResultSet() .records [0]; //有关联!
me.getOrderStore()。add(savedRecord);
me.getOrderContentStore()。add(savedRecord.getContents()); //协会!
me.getOrderAddressStore()。add(savedRecord.getAddress()); //协会!
break;

case'update':
//从服务器
break查找并更新记录与响应;
}
}

我的应用服务器收到 PurchaseOrder 并处理相应的数据保存。我不会详细介绍,因为这个过程很大程度上取决于你自己的实现。我的应用程序框架宽松地基于Zend 1.11(主要是利用 Zend_Db )。



我觉得这是最好的方法由于以下原因:




  • 客户端上不存在各种各样的model.save()回调的混乱字符串

  • 只有一个请求,这很容易管理

  • 原子性很容易在应用程序服务器上处理

  • 较少的往返行程=没有担心

  • 如果你真的很懒,回调的成功方法可以简单地重新加载商店。



我会让这个答案坐下来鼓励讨论。

感谢阅读!


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 i.e., 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 (e.g., 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 (e.g., 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:

  • No messy string of various model.save() callbacks on the client
  • Only one request, which is very easy to manage
  • Atomicity is easily handled on the application server
  • Less round trips = less potential points of failure to worry about
  • If you're really feeling lazy, the success method of the callback can simply reload stores.

I will let this answer sit for a bit to encourage discussion.

Thanks for reading!

这篇关于ExtJS和复杂保存操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆