Ember.js 如何回滚数据中的关系更改

Ember.js 如何回滚数据中的关系更改,ember.js,ember-data,relationships,Ember.js,Ember Data,Relationships,我有两种亲子关系模式:培训和锻炼: App.Training=DS.Model.extend({ 练习:DS.hasMany('App.Exercise') }) App.Exercise=DS.Model.extend({ 培训:DS.belongsTo('App.training') }) 我想有一个页面,其中显示培训及其所有相关练习。如果用户按下Edit按钮,页面将变为可编辑,并可能添加新练习。我还想要一个取消按钮,该按钮将放弃所做的所有更改 这是我的控制器: App.trainings

我有两种亲子关系模式:培训和锻炼:

App.Training=DS.Model.extend({
练习:DS.hasMany('App.Exercise')
})
App.Exercise=DS.Model.extend({
培训:DS.belongsTo('App.training')
})
我想有一个页面,其中显示培训及其所有相关练习。如果用户按下
Edit
按钮,页面将变为可编辑,并可能添加新练习。我还想要一个
取消
按钮,该按钮将放弃所做的所有更改

这是我的控制器:

App.trainingshowcontroller=Em.ObjectController.extend({
编辑:错,
编辑:函数(){
此.set('editing',true);
transaction=this.get('store').transaction();
transaction.add(this.get('model'));
this.get('model.exercises').forEach(函数(x){
交易记录。添加(x);
});
},
取消:函数(){
此.set('editing',false);
this.get('model.transaction').rollback();
},
保存:函数(){
此.set('editing',false);
this.get('model.transaction').commit();
},
addExercise:function(){
this.get('model.exercises').createRecord({});
}
})
控制器中有四个事件处理程序:

  • edit
    :用户按下
    edit
    按钮:创建事务,页面进入“编辑”模式
  • 取消
    :用户按下了
    取消
    按钮:事务回滚并返回到“正常”模式
  • save
    :用户按下
    save
    按钮:事务提交并返回“正常”模式
  • addExercise
    :用户按下了
    addExercise
    按钮:将创建一个新的练习(在同一事务中)并将其添加到培训中
  • 除了新创建的记录外,回滚功能工作正常:如果我按下
    编辑
    按钮,添加新练习并按下
    取消
    按钮,新创建的练习将保留在页面上

    什么是摆脱被丢弃的儿童记录的最佳方法

    更新:

    我创建了一个JSFIDLE来重现这个问题,但它成功了。与这里的应用程序不同,我使用了
    DS.FixtureAdapter

    然后我使用
    DS.RESTAdapter
    创建了另一个,问题出现了:

    在小提琴中尝试:编辑,添加新的,然后回滚

    我发现,在RESTAdapter的情况下,当我向
    hasMany
    关系添加新的子记录时,父记录不会变脏。这似乎很好,但当我回滚事务时,新创建的子记录将保留在父级的
    ManyArray


    我仍然不知道,处理这种情况的最佳方法是什么。

    这不太好,但您可以通过手动弄脏父记录来强制它回滚:

    parent.send('becomeDirty');
    parent.rollback();
    parent.get('children.length'); // => 0
    

    @托塔达和其他读者跟随。从
    Ember Data:1.0.0-beta.10+canary.7db210f29a开始
    当回滚子级时,父级仍然不能使
    parentTraining.isDirty()
    的值为true。当一个属性被更改时,Enbe数据会考虑一个父记录,但是当<代码> DS时,Engult>不< /强> .HasMule数组有更改(工作,因此您可以更新服务器上的父属性的任何更改)。
    对于上面提到的情况,要对新创建的子记录执行
    rollback()
    ,解决方法是将要丢弃的子记录上的
    .rollback()
    替换为
    .deleteRecord()
    。然后,余烬数据自动知道将其从
    DS中删除。然后,有许多
    数组,您可以拍拍自己的后背,以获得出色的回滚效果

    余烬数据中严重缺乏对hasMany和belongsTo关系进行适当的脏检查和回滚。它当前的行为方式通常被报告为bug。这对于许多开发人员来说是一个巨大的痛点,这里正在讨论如何解决这个问题:

    在找到合适的解决方案之前,您可以使用以下方法解决此问题

    首先,您需要重新打开DS.Model并对其进行扩展。如果您使用的是globals,您可以将它(例如DS.Model.reopen({}))放在任何地方,但是如果您使用的是Ember CLI,最好创建一个初始值设定项(例如Ember g初始值设定项Model):

    上面的代码本质上存储了加载或更新时的原始关系,以便以后可以用于回滚和脏检查

    model.rollback()现在应该回滚所有内容,包括hasMany和belongsTo关系。不过,我们还没有完全解决“isDirty”检查问题。为此,我们需要在模型的具体实现中覆盖isDirty。我们之所以需要在这里执行此操作,而不能在DS.Model中一般地执行此操作,是因为DS.Model不知道要监视哪些属性更改。下面是一个使用Ember CLI的示例。globals也会使用相同的方法,只是您会将此类分配给类似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.[]', 'authors.@each.isDirty').readOnly()
    
    });
    
    export default Book;
    

    对于isDirty的依赖参数,请确保包括所有belongsTo关系,并为每个hasMany关系包括'array.[]'和'array.@each.isDirty'。现在isDirty应该如预期的那样工作了。

    晚会迟到了,但现在我们开始:

    我创建了一个插件来解决这个问题。 只需调用
    rollbackrelations()
    ,它将回滚您的所有关系(belongsTo&hasMany)。有关更多选项,请参阅自述文件


    这是一个好主意,但现在我的应用程序似乎正在立即加载所有异步关系(这需要一段时间),而不是等到实际使用异步关系?如果我错了,请纠正我。@justastefan,观察得好。saveOriginalRelations可能正在加载所有异步关系。如果你有
    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.[]', 'authors.@each.isDirty').readOnly()
    
    });
    
    export default Book;