4

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

我正在尝试使用扩展默认 RESTAdapter 的适配器。所有应用程序都可以正常工作,但双重 hasMany 关系会引发异常。深入研究代码,inverseBelongsToForHasMany 方法会引发异常。

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

  1. 这是否受支持,问题只是我做错了什么?
  2. 如果不支持,是否计划出现的功能?
  3. 这是在此类应用程序中要避免的关联类型吗?如果是这样,哪个是最好的方法或解决方法?

提前致谢

4

2 回答 2

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'); 
  }
});

这只是起点。然后,您需要自定义模型和适配器,以便以工作方式发送/接收/保留记录

例如,在我们的应用程序中,我们{ includedJoin: true }在 hasMany 关系中引入了一个选项,并将连接表声明为 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;
  }
}

在服务器端,我们使用带有 ActiveModelSerializer 的 Rails,所以唯一的小技巧定制是当我们更新父模型时,我们手动管理连接关系,并在连接表中创建/删除条目。

于 2012-11-09T08:16:37.107 回答
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 对象,follow 方法只是将该用户添加到两个关联的部分。

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

虽然它没有想象中的那么优雅,但我们最大的动机是当 Ember Data 更新时,我们应该能够更容易地将其转换为简单的 Ember Data 支持版本,而不是我们弄乱了 Store 本身。

于 2012-11-09T20:58:57.963 回答