问题 ExtJS 4.1 - 在Model.Save()响应中返回关联数据
我很好奇为什么记录包含在结果集中 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
请求使用单个模型及其相关数据。这是所有工作hunky dory!
服务器对READ请求的响应
{
"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 - 在记录保存时加载嵌套数据 但没有回应。我觉得我的问题要更加彻底......
编辑: 我在Sencha论坛上发布了这个问题: http://www.sencha.com/forum/showthread.php?270336-Associated-Data-in-Model.save()-Response
编辑(2013年8月23日): 我用一个完整的例子重写了这篇文章,以及其他发现......
4665
2017-08-16 20:19
起源
答案:
我发现了这个问题,或者更确切地说, 混乱 在于 getRecords()
的方法 Ext.data.Operation
。此方法返回 “虽然代理可能会在初始化操作后的某个时刻修改这些记录的数据,但会返回操作的初始配置记录。” 根据文件。
这是相当令人困惑的IMO,因为返回的记录确实更新了,但是生成的关联存储以及相关的数据不是!这就是导致我混淆的原因,似乎记录包含来自应用程序服务器的更新数据,但事实并非如此。
为了帮助我简单的心灵获得 FULLY 来自响应的更新数据,我已经添加了一个方法 Ext.data.Operation
class ...我刚刚写了这个方法,并没有测试它比确保我正在寻找的功能,所以使用风险自负!
请记住,我不调用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
*/
}
});
编辑12/10/13
我还添加了一个方法 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;
}
所以基本上我做这样的事情(这理论上会在订单控制器中)
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;
}
}
});
}
我希望这可以帮助那些像我一样困惑的人!
6
2017-08-23 15:57
完全同意你的看法。真奇怪的行为。它应该更新记录上的关联存储。这就是我解决这个问题的方法(基本上只是通过读者运行响应!):
success: function(record, operation) {
var newRecord= me.getMyModel().getProxy().reader.read(operation.response).records[0];
}
4
2017-10-29 00:07
答案:
我发现了这个问题,或者更确切地说, 混乱 在于 getRecords()
的方法 Ext.data.Operation
。此方法返回 “虽然代理可能会在初始化操作后的某个时刻修改这些记录的数据,但会返回操作的初始配置记录。” 根据文件。
这是相当令人困惑的IMO,因为返回的记录确实更新了,但是生成的关联存储以及相关的数据不是!这就是导致我混淆的原因,似乎记录包含来自应用程序服务器的更新数据,但事实并非如此。
为了帮助我简单的心灵获得 FULLY 来自响应的更新数据,我已经添加了一个方法 Ext.data.Operation
class ...我刚刚写了这个方法,并没有测试它比确保我正在寻找的功能,所以使用风险自负!
请记住,我不调用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
*/
}
});
编辑12/10/13
我还添加了一个方法 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;
}
所以基本上我做这样的事情(这理论上会在订单控制器中)
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;
}
}
});
}
我希望这可以帮助那些像我一样困惑的人!
6
2017-08-23 15:57
完全同意你的看法。真奇怪的行为。它应该更新记录上的关联存储。这就是我解决这个问题的方法(基本上只是通过读者运行响应!):
success: function(record, operation) {
var newRecord= me.getMyModel().getProxy().reader.read(operation.response).records[0];
}
4
2017-10-29 00:07
如果您的ID字段有值,则ExtJS将始终调用update。如果您没有向id字段写入任何值或将其设置为null,则应调用create。我猜你试图用现有记录调用save,所以它总是会调用update。这是一种理想的行为。
-1
2017-12-24 15:01