我有一个应用程序逻辑,需要两个模型具有互惠的hasMany关系。举个例子,想象一下可以用几个标签标记的一组GitHub问题。
我正在尝试使用扩展默认RESTAdapter的适配器。所有应用程序都运行正常,但double hasMany关系会抛出异常。深入研究代码,inverseBelongsToForHasMany方法抛出异常。
所以,我猜Ember.Data不支持两个模型与两侧的hasMany关系的关联,并且每个hasMany都需要关联的belongsTo。我的问题是:
提前致谢
答案 0 :(得分:8)
ember-data尚不支持多对多关系。目前,一种可能的解决方法是手动管理连接表。
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 ...
});
然后在Adapter中,我们覆盖create / update / delete方法,以忽略商店中的连接表生命周期
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,所以唯一一个棘手的定制是当我们更新父模型时,我们手动管理连接关系,并在连接表中创建/删除条目。
答案 1 :(得分:8)
我们使用类似的方法来创建关联对象。但是,我们只是将连接对象添加到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对象,而follow方法只会将该用户添加到关联的部分中。
要删除,它会弹出关联的对象并销毁关联对象。
虽然它没有那么优雅,但我们的主要动机是,当Ember Data得到更新时,我们应该能够将它转换为简单的股票Ember Data支持的版本比我们与商店混淆时更容易本身。