ExtJS 4.1-在Model.Save()响应中返回关联数据

问题描述 投票:12回答:4

我很好奇为什么Model.save()响应的结果集中包含的记录不能正确返回更新的关联数据,尽管更新的数据包含在服务器响应中...

示例型号和商店定义:

Ext.define("App.model.test.Parent",{
    extend: 'Ext.data.Model',
    requires: ['App.model.test.Child'],
    fields: [
            {name: 'id', type: 'int' },
            {name: 'name', type: 'string'},
            {name: 'kids', type: 'auto', defaultValue: []}
    ],
    idProperty: 'id',

    hasMany: [{
            foreignKey: 'parent_id',
            model: 'App.model.test.Child', 
            associationKey: 'kids',
            name: 'getKids'   
    }],

    proxy: {
        type: 'ajax',
        api : {
            create: '/service/test/create/format/json',
            read : '/service/test/read/format/json',
            update : '/service/test/update/format/json'
        },

        reader: {
            idProperty      : 'id',
            type            : 'json',
            root            : 'data',        
            successProperty : 'success',       
            messageProperty : 'message'
        },

        writer: {
            type            : 'json',
            writeAllFields  : true
        }
    }
});

Ext.define("App.model.test.Child",{
    extend: 'Ext.data.Model',
    fields: [
        {name: 'id', type: 'int' },
        {name: 'name', type: 'string'},
        {name: 'parent_id', type: 'int'}
    ]
});

Ext.define("App.store.test.Simpson",{
    storeId: 'TheSimpsons',
    extend: 'Ext.data.Store',
    model : 'App.model.test.Parent',
    autoLoad: true,
    autoSync: false
});

应用服务器使用单个模型以及其关联数据对代理的READ请求进行响应。这都是工作正常的海ry!

服务器对读取请求的响应

{
"data":{
    "id":1,
    "name":"Homer Simpson",
    "children":{
        "1":{
            "id":1,
            "name":"Bart Simpson"
        },
        "2":{
            "id":2,
            "name":"Lisa Simpson"
        },
        "3":{
            "id":3,
            "name":"Maggie Simpson"
        }
    }
},
"success":true,
"message":null
}

到目前为止,一切都按计划进行...

store = Ext.create("App.store.test.Simpson");
homer = store.getById(1);
kids  = homer.getKids().getRange();
console.log("The Simpson Kids", kids);  // [>constructor, >constructor, >constructor]

具有保存和更新请求的意外行为开始

这是我对UPDATE请求的测试响应...

/** Server UPDATE Response */
{
"data":{
    "id":1,
    "name":"SAVED Homer Simpson",
    "kids":[{
        "id":1,
        "name":"SAVED Bart Simpson",
        "parent_id":1
    },{
        "id":2,
        "name":"SAVED Lisa Simpson",
        "parent_id":1
    },{
        "id":3,
        "name":"SAVED Maggie Simpson",
        "parent_id":1
    }]
},
"success":true,
"message":null
}


/** Will call proxy UPDATE, response is above */
homer.save({
    success: function(rec, op){
        var savedRec = op.getRecords().pop(),
            kidNames = '';
        console.log(savedRec.get('name')); // SAVED Homer Simpson = CORRECT!
        Ext.each(savedRec.getKids().getRange(), function(kid){
            kidNames += kid.get('name') + ", ";
        });
        console.log(kids); 
        //Outputs: Bart Simpson, Lisa Simpson, Maggie Simpson = WRONG!!
    }
})

[我注意到,如果我检查服务器返回的记录,则所包含的记录所生成的关联存储(即getKidsStore)是原始记录,即它们的名称中没有“ SAVED”。返回记录的kids属性,但是确实包含正确的数据。

如果我正确理解了该问题,则是Ext.data.reader.Reader无法正确地使用.save()响应中包含的关联数据来更新关联存储。如果是这样,我认为这是非常不直观的,因为我希望与处理store.load()请求并填充生成的关联存储的读取器具有相同的行为。

有人能指出我正确的方向来实现我所追求的行为吗?

免责声明:此处提出了相同的问题:ExtJs 4 - Load nested data on record save,但没有响应。我觉得我的问题要更彻底。.

EDIT:我已经在Sencha论坛上发布了这个问题:http://www.sencha.com/forum/showthread.php?270336-Associated-Data-in-Model.save()-Response

编辑(8/23/13):我用一个完整的例子以及其他发现重写了这篇文章……

extjs nested associations extjs4.1
4个回答
6
投票
我发现了问题,或更确切地说,

confusion处于getRecords()Ext.data.Operation方法中。此方法返回“尽管该操作初始化后,代理可能会在某些时候修改这些记录的数据,但是将返回该操作的初始配置记录。”根据文档。这确实使IMO感到困惑,因为返回的记录确实已更新,但是生成的关联存储以及关联数据却没有!这就是导致我感到困惑的原因,似乎记录中包含来自应用程序服务器的更新数据,但事实并非如此。

为了帮助我的头脑简单地从响应中获取

FULLY

更新的数据,我向Ext.data.Operation类中添加了一个方法...我只是编写了此方法,并且对其进行的测试不超过确保我正在寻找的功能,因此使用后果自负![请记住,我不调用store.sync(),而是实例化模型并调用model.save()方法,所以我的resultSet通常只包含一条记录...

Ext.override(Ext.data.Operation,{ getSavedRecord: function(){ var me = this, // operation resultSet = me.getResultSet(); if(resultSet.records){ return resultSet.records[0]; }else{ throw "[Ext.data.Operation] EXCEPTION: resultSet contains no records!"; } } });

现在我已经能够实现我所追求的功能...

// Get the unsaved data store = Ext.create('App.store.test.Simpson'); homer = store.getById(1); unsavedChildren = ''; Ext.each(homer.getKids().getRange(), function(kid){ unsavedChildren += kid.get('name') + ","; }); console.log(unsavedChildren); // Bart Simpson, Lisa Simpson, Maggie Simpson // Invokes the UPDATE Method on the proxy // See original post for server response home.save({ success: function(rec, op){ var savedRecord = op.getSavedRecord(), // the magic! /sarcasm savedKids = ''; Ext.each(savedRecord.getKids().getRange(), function(kid){ savedKids += kid.get('name') + ','; }); console.log("Saved Children", savedKids); /** Output is now Correct!! SAVED Bart Simpson, SAVED Lisa Simpson, SAVED Maggie Simpson */ } });

编辑13/10/12我还向Ext.data.Model添加了一个方法,称为updateTo,该方法用于将记录更新为提供的记录,该记录还处理关联。我将其与上面的getSavedRecord方法结合使用。请注意,这不处理任何belongsTo关联,因为我不在我的应用程序中使用它们,但是该功能很容易添加。

/** * Provides a means to update to the provided model, including any associated data * @param {Ext.data.Model} model The model instance to update to. Must have the same modelName as the current model * @return {Ext.data.Model} The updated model */ updateTo: function(model){ var me = this, that = model, associations = me.associations.getRange(); if(me.modelName !== that.modelName) throw TypeError("updateTo requires a model of the same type as the current instance ("+ me.modelName +"). " + that.modelName + " provided."); // First just update the model fields and values me.set(that.getData()); // Now update associations Ext.each(associations, function(assoc){ switch(assoc.type){ /** * hasOne associations exist on the current model (me) as an instance of the associated model. * This instance, and therefore the association, can be updated by retrieving the instance and * invoking the "set" method, feeding it the updated data from the provided model. */ case "hasOne": var instanceName = assoc.instanceName, currentInstance = me[instanceName], updatedInstance = that[instanceName]; // Update the current model's hasOne instance with data from the provided model currentInstance.set(updatedInstance.getData()); break; /** * hasMany associations operate from a store, so we need to retrieve the updated association * data from the provided model (that) and feed it into the current model's (me) assocStore */ case "hasMany": var assocStore = me[assoc.storeName], getter = assoc.name, newData = that[getter]().getRange(); // Update the current model's hasMany association store with data from the provided model's hasMany store assocStore.loadData(newData); break; // If for some reason a bogus association type comes through, throw a type error // At this time I have no belongsTo associations in my application, so this TypeError // may one day appear if I decide to implement them. default: throw TypeError("updateTo does not know how to handle association type: " + assoc.type); break; } }); // Commit these changes me.commit(); return me; }

所以基本上我会做类似的事情(理论上在Order控制器中)

doSaveOrder: function(order){ var me = this, // order controller orderStore = me.getOrderStore(); // magic method // Save request order.save({ scope: me, success: function(responseRecord, operation){ // note: responseRecord does not have updated associations, as per post var serverRecord = operation.getSavedRecord(), storeRecord = orderStore.getById(order.getId()); switch(operation.action){ case 'create': // Add the new record to the client store orderStore.add(serverRecord); break; case 'update': // Update existing record, AND associations, included in server response storeRecord.updateTo(serverRecord); break; } } }); }

我希望这可以帮助像我一样困惑的人! 

4
投票
完全同意您的意见。真是奇怪的行为。它应该更新记录上的关联存储。这就是我如何解决此问题的方法(基本上只是通过阅读器运行响应!):

0
投票
在ExtJS 6.2中,问题仍然存在(或再次存在)。我的解决方案:

-1
投票
如果您的ID字段具有值,则ExtJS将始终调用update。如果您没有将任何值写入ID字段或将其设置为null,则应调用create。我猜您正在尝试使用现有记录调用保存,因此它将始终调用更新。这是期望的行为。
© www.soinside.com 2019 - 2024. All rights reserved.