2012-11-08 45 views
4

我有一个应用程序逻辑,需要两个模型具有相互具有许多关系。举个例子,想象一下可以用几个标签标记的一组GitHub问题。EmberData:与hasMany关系相关的两个模型

我想使用扩展默认RESTAdapter的适配器。所有的应用程序都能正常工作,但double有许多关系会引发异常。深入研究代码,inverseBelongsToForHasMany方法抛出异常。

因此,我猜Ember.Data不支持两个模型与hasMany关系在两侧的关联,并且每个hasMany都需要一个关联的belongsTo。我的问题是:

  1. 这是支持和问题只是我做错了什么?
  2. 如果不支持,它是计划显示的功能吗?
  3. 这是一种在这类应用中要避免的关联类型吗?如果是这样,哪种方法或解决方法最好?

在此先感谢

回答

8

我们使用类似的方法创建关联对象。但是,我们不是重写store中的方法,而是将联接对象添加到api中。

所以在我们的模型创建:

App.Hashtag = DS.Model.extend({ 
    hashtagUsers: DS.hasMany('App.HashtagUser', {key: 'hashtag_user_ids'}) 
}); 

App.User = DS.Model.extend({ 
    hashtagUsers: DS.hasMany('App.HashtagUser', {key: 'hashtag_user_ids'}) 
}); 

App.HashtagUser = DS.Model.extend({ 
    user: DS.belongsTo('App.User'), 
    hashtag: DS.belongsTo('App.Hashtag') 
}); 

然后进行交易,我们简单地改变并提交加盟对象。

App.UserController = Ember.ObjectController.extend({ 
    followHashtag: function(tag) { 
    var hashtagUser; 
    hashtagUser = this.get('hashtagUsers').createRecord({ 
     hashtag: tag 
    }); 
    tag.get('hashtagUsers').pushObject(hashtagUser); 
    App.store.commit(); 
    } 
    unfollowHashtag: function(tag) { 
    var itemToRemove; 
    itemToRemove = this.get('hashtagUsers').find(function(hashtagUser) { 
     if (hashtagUser.get('hashtag') === this) { 
     return true; 
     } 
    }, tag); 
    this.get('hashtagUser').removeObject(itemToRemove); 
    tag.get('hashtagUser').removeObject(itemToRemove); 
    itemToRemove.deleteRecord(); 
    App.store.commit(); 

});

该API创建一个HashtagUser对象,下面的方法只是将该用户添加到两个关联的部分。

对于删除,它会弹出关联的对象并销毁关联对象。

尽管它没有那么优雅,但我们最大的动力是,当Ember Data得到更新时,我们应该能够更容易地将它转换为一个简单的Ember Data支持版本,而不是如果我们与存储自己。

+0

在最新版本的Ember Data中,您可以使用App.ApplicationSerializer = DS.ActiveModelSerializer.extend({});'使用下划线的外键。 – rxgx

8

多对多关系尚不支持烬数据。目前,一种可能的解决方法是手动管理连接表。

A = DS.Model.extend({ 
    abs: DS.hasMany('Ab'), 

    bs: function() { 
    return this.get('abs').getEach('b'); 
    } 
}); 

Ab = DS.Model.extend({ 
    a: DS.belongsTo('A'), 
    b: DS.belongsTo('b') 
}); 

B = DS.Model.extend({ 
    abs: DS.hasMany('Ab'), 

    bs: function() { 
    return this.get('abs').getEach('a'); 
    } 
}); 

这只是一个起点。你需要再自定义您的模型和适配器,以发送/接收的工作方式

例如/坚持记录,在我们的应用程序,我们引入的hasMany关系内的{ includedJoin: true }选项,并宣布将加入表作为一个JoinModel

A = DS.Model.extend({ 
    abs: DS.hasMany('Ab', {includeJoin: true}), 
    ... 
}); 

DS.JoinModel = DS.Model.extend(); 

Ab = DS.JoinModel.extend({ 
    ... belongsTo relationships ... 
}); 

然后在适配器,我们覆盖了创建/更新/以忽略在店里,我们在连接表的生命周期

createRecords: function (store, type, records) { 
    if (!DS.JoinModel.detect(type)) { 
    this._super(store, type, records); 
    } 
} 

最后,在串行删除方法乘坐addHasMany函数以便将加入数据作为父模型中的嵌入式ID发送到服务器。

addHasMany: function (hash, record, key, relationship) { 
    var 
    options = relationship.options, 
    children = []; 

    //we only add join models, use of `includeJoin` 
    if (options.includedJoin) { 
    record.get(relationship.key).forEach(function (child) { 
     children.pushObject(child.toJSON({ 
     includeId: true 
     })); 
    }); 
    hash[key] = children; 
    } 
} 

服务器端,我们使用Rails与ActiveModelSerializer,所以只能小技巧 - 定制就是当我们更新父模型,我们手动管理连接关系,创建/删除连接表项。

+0

感谢您的详细回复。手动处理关系是我们知道的起点,但是对适配器/序列化程序中必须完成的更改的详细分析是惊人的。 – escalant3

+0

很高兴知道它可以帮助你:)。这不是完美的,显然是黑客,但它似乎对我们有用。我希望你能成功实现服务器端的工作。 –

相关问题