删除Ember HasMany

时间:2014-10-21 19:30:41

标签: ember.js ember-data

我使用Ember-Data和[Kurko的Ember Data IndexedDB适配器](https://github.com/kurko/ember-indexeddb-adapter)与多个hasMany关系使用Ember.js。我能够成功添加hasMany关系而没有任何问题。我的问题在于删除hasMany关系。

App.Race = DS.Model.extend({
    name: DS.attr('string'),
    ...
    athletes: DS.hasMany('athlete', {async: true}),
    ...
});

App.Athlete = DS.Model.extend({
    bib: DS.attr('number'),
    name: DS.attr('string'),
    ...
    splits: DS.hasMany('split', {async: true}),
    races: DS.hasMany('race', {async: true}),
    ...
});

App.Split = DS.Model.extend({
    distance: DS.attr('string'),
    time: DS.attr('string'),
    athlete: DS.belongsTo('athlete', {async:true}),
    race: DS.belongsTo('race', {async: true}),
    ...
});

在删除运动员时,有时会从指定的athlete模型中删除race引用,从而导致应用程序中断。始终会删除athlete模型,并始终删除所有必需的splits模型。我知道它与我的存储的异步性质有关,但我无法在行动中找出问题:

removeAthlete: function() {
    var self = this,
    athlete = this.get('model');

    // Get race from athlete
    athlete.get('races').then(function(races){

        // Remove athlete from races
        races = races.toArray();
        races.forEach(function(race){

            console.log('removing athlete from race');
            race.get('athletes').removeObject(athlete);
            race.save();
        }); 
        // destroy splits
        athlete.get('splits').then(function(splits) {
            console.log('retrieved splits');
            splits.toArray().forEach(function(split) {
                console.log('removing split');
                split.destroyRecord();
            });

            // destroy athlete
            athlete.destroyRecord();
        });
    }); 
},
...

修改

经过一些通知尝试后,我意识到该错误与从竞赛中删除athlete引用有关。随着我的进步,我会给予更多更新。

1 个答案:

答案 0 :(得分:1)

在为这个问题研究JSBin时,我能够弄清楚问题是什么以及如何解决它。希望我能说出来。问题在于我对存储的异步调用的嵌套(或缺乏)。

removeAthlete方法中,我没有将异步调用嵌套到我的存储容器中,这导致athlete.destroyRecord()被过早调用。

removeAthlete: function() {
    var self = this,
    athlete = this.get('model');

    athlete.get('races').then(function(races){    // Get race from athlete

        races = races.toArray();
        races.forEach(function(race){ // Remove athlete from each race
            race.get('athletes').removeObject(athlete);
            race.save();
        }); 

        // async call to splits
        athlete.get('splits').then(function(splits) {
            // destroy each split
            splits.toArray().forEach(function(split) {
                split.destroyRecord();
            });

            /* 
            call to destroy athlete is called while other async calls are 
            waiting to get responses
            */
            athlete.destroyRecord();
        });

    }); 
},

异步调用在等待响应时继续执行代码,因此在收到异步响应之前调用每个异步调用之后的代码。根据{{​​1}}数组中的拆分数量,可以在执行前一行中的代码之前调用splits。如果athlete.destroyRecord较少,则splits会尽快被调用。如果还有更多,则稍后调用athlete.destroyRecord,之后调用所有前面的行。所以我的解决方案是:

athlete.destroyRecord

通过这种方式,依次调用依赖于其他异步调用结果的每个异步调用。仅在removeAthlete: function() { var self = this, athlete = this.get('model'); // Get race from athlete athlete.get('races').then(function(races){ // Remove athlete from races races = races.toArray(); races.forEach(function(race){ race.get('athletes').removeObject(athlete); race.save().then(function(){ if(races.indexOf(race) === races.get('length') -1) { athlete.get('splits').then(function(splits) { splits.toArray().forEach(function(split) { split.destroyRecord(); }); // destroy athlete athlete.destroyRecord(); }); } }); }); }); }, 移除所有splits后才会删除athletes。我希望找到一个更简单,更有效的解决方案。这似乎不是最好的方法。所以我不会将此标记为正确的答案。希望其他人知道更好的方法。