EmberData:与hasMany关系相关的两个模型

时间:2012-11-08 23:47:29

标签: ember.js ember-data

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

我正在尝试使用扩展默认RESTAdapter的适配器。所有应用程序都运行正常,但double hasMany关系会抛出异常。深入研究代码,inverseBelongsToForHasMany方法抛出异常。

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

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

2 个答案:

答案 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支持的版本比我们与商店混淆时更容易本身。