Ember 数据中非常缺乏对 hasMany 和 BelongsTo 关系进行适当的脏检查和回滚。它当前的行为方式经常被报告为错误。这对很多开发人员来说是一个很大的痛点,这里正在讨论如何解决这个问题:
https://github.com/emberjs/rfcs/pull/21
在找到适当的解决方案之前,您可以使用以下方法解决此问题。
首先,您需要重新打开 DS.Model 并扩展它。如果您使用全局变量,则可以将其(例如 DS.Model.reopen({}))放在任何地方,但如果您使用 Ember CLI,最好创建一个初始化程序(例如 ember g 初始化程序模型):
import DS from 'ember-data';
export function initialize(/* container, application */) {
DS.Model.reopen({
saveOriginalRelations: function() {
this.originalRelations = {};
this.constructor.eachRelationship(function(key, relationship) {
if (relationship.kind === 'belongsTo')
this.originalRelations[key] = this.get(key);
if (relationship.kind === 'hasMany')
this.originalRelations[key] = this.get(key).toArray();
}, this);
},
onLoad: function() {
this.saveOriginalRelations();
}.on('didLoad', 'didCreate', 'didUpdate'),
onReloading: function() {
if (!this.get('isReloading'))
this.saveOriginalRelations();
}.observes('isReloading'),
rollback: function() {
this._super();
if (!this.originalRelations)
return;
Ember.keys(this.originalRelations).forEach(function(key) {
// careful, as Ember.typeOf for ArrayProxy is 'instance'
if (Ember.isArray(this.get(key))) {
this.get(key).setObjects(this.originalRelations[key]);
this.get(key).filterBy('isDirty').invoke('rollback');
return;
}
if (Ember.typeOf(this.get(key)) === 'instance') {
this.set(key, this.originalRelations[key]);
return;
}
}, this);
},
isDeepDirty: function() {
if (this._super('isDirty'))
return true;
if (!this.originalRelations)
return false;
return Ember.keys(this.originalRelations).any(function(key) {
if (Ember.isArray(this.get(key))) {
if (this.get(key).anyBy('isDirty'))
return true;
if (this.get(key).get('length') !== this.originalRelations[key].length)
return true;
var dirty = false;
this.get(key).forEach(function(item, index) {
if (item.get('id') !== this.originalRelations[key][index].get('id'))
dirty = true;
}, this);
return dirty;
}
return this.get(key).get('isDirty') || this.get(key).get('id') !== this.originalRelations[key].get('id');
}, this);
}
});
};
export default {
name: 'model',
initialize: initialize
};
上面的代码本质上存储了加载或更新时的原始关系,以便稍后可以用于回滚和脏检查。
model.rollback() 现在应该回滚所有内容,包括 hasMany 和 BelongsTo 关系。不过,我们还没有完全解决“isDirty”检查问题。为此,我们需要在模型的具体实现中重写 isDirty。我们需要在这里执行此操作而不能在 DS.Model 中通用执行此操作的原因是因为 DS.Model 不知道要监视哪些属性更改。以下是使用 Ember CLI 的示例。相同的方法将用于全局变量,只不过您将此类分配给 App.Book 之类的东西:
import DS from 'ember-data';
var Book = DS.Model.extend({
publisher: DS.belongsTo('publisher'),
authors: DS.hasMany('author'),
isDirty: function() {
return this.isDeepDirty();
}.property('currentState', 'publisher', 'authors.[]', '[email protected]').readOnly()
});
export default Book;
对于 isDirty 的依赖参数,请确保包含所有 ownTo 关系,并且还包含“array.[]”和“[电子邮件受保护]' 对于每个 hasMany 关系。现在 isDirty 应该按预期工作。