3

我已经看过文档好几次了,但这方面我仍然不清楚。我认为骨干关系完全有可能做一些它没有做的事情。

我正在寻找基于键定义关系的方法,以避免所有的样板文件都是胡说八道。

以规范的艺术家和专辑为例:一个艺术家有许多专辑,由专辑.artist_id 定义

/api/artist/62351 可能会返回

{
  id: 62351,
  name:"Jimi Hendrix"
}

同样 /api/album?artist_id=62351 可能会返回

[
 {
   id:5678,
   name: "Are You Experienced?"
   artist_id: 62351
 },
 {
   id: 4321,
   name: "Axis: Bold as love",
   artist_id: 62351
 }
]

我如何定义艺术家和专辑关系,这样

var hendrixInstance = new Artist({id:62351});
hendrixInstance.get('albums');

会根据专辑foreign_key Artist_id 获取并返回专辑集合吗?它一定只是我还没有尝试过的 key/keySource/keyDestination 的一些排列,或者是骨干关系没有试图解决的问题,但是我的 doc groking 失败了,我认为对此有一个简明的答案SO 可能会帮助未来的 Google 员工。

var Artist = Backbone.RelationalModel.extend({
  urlRoot: '/api/artist',
  relations:[{
    key: 'albums', //Docs say this is the foreign key name, but in practice it doesn't appear that way. Need keySource/Destination?
    type: Backbone.HasMany,
    reverseRelation: {
      key: 'artist',
      type: Backbone.HasOne
    }
  }]
});
var Album = Backbone.RelationalModel.extend({
  urlRoot: '/api/album'
});

奖励指向一个示例模型,该模型使用 parent_id 引用其自身邻接列表样式

4

2 回答 2

3

所以,@xzhang 上面的方法让我一直在迭代这个问题。首先,我很想在这方面被证明是错误的,但我还没有找到一种无需额外自定义代码就可以让骨干关系处理这个问题的方法。由于在我看来这是一个非常基本的 OneToMany 关系示例,我仍然希望我只是没有得到明显的东西。

这就是我最终为处理这种情况所做的事情。不幸的是,当调用 someobject.fetch('somerelationship') 时,它仍然不会自动从服务器获取,这是我真正想要的。parse 函数对大多数人来说不是必需的,但它是我调用的 api 所必需的。

首先,我建立了一个基础集合来扩展:

  var BaseCollection = Backbone.Collection.extend({
    initialize: function(models, options) {
      if (_.isObject(options.relation)) {
      this.url = '/api/'
        + options.relation.keySource
        + '?search.'+options.relation.reverseRelation.keySource
        + '=' + options.foreignId;
      }
    },
    parse: function(res) { return res.success ? res.list : res },
  });

然后是一个可重用的辅助函数(可能会滚动到 BaseCollection 中)来帮助创建关系

  function collectionOptions(instance) {
    return {"relation":this, "foreignId":instance.get('id') };
  };

最后,这些关系被告知使用 BaseCollection 作为它们的 CollectionType,collectionOptions() 助手被分配来设置 collectionOptions。

 var Form = BaseModel.extend({
    urlRoot: '/api/form',
    relations:[
      {
        key: 'fills',
        keySource: 'fill',
        relatedModel: Fill,
        type: Backbone.HasMany,
        collectionOptions: collectionOptions,
        collectionType: BaseCollection,
        reverseRelation: {
          key: 'form',
          keySource: 'form_id',
          type: Backbone.HasOne
        }
      },{
        key: 'children',
        keySource: 'form',
        relatedModel: 'Form',
        type: Backbone.HasMany,
        collectionOptions: collectionOptions,
        collectionType: BaseCollection,
        reverseRelation: {
          key: 'parent',
          keySource: 'parent_id',
          type: Backbone.HasOne
        }
      }
    ]
  });

这使我可以避免更改服务器端 API 以返回 id 列表,然后单独获取这些 id。相反,我可以:

var form = new Form({id:1});
form.get('children').fetch();
form.toJSON(); //now has {id:1, ..., ..., children:[child,child,child,...]}

在第一次调用 .get('children') 时对 autoFetch 子项的扩展只是门票,但我还没有发现如何在不修改骨干关系本身的情况下做到这一点。

于 2013-04-16T14:24:15.450 回答
0

我正面临着确切的问题(Backbone-relational hasmany best practice),经过 2 天的研究并查看源代码,我认为 key/keySource/keyDestination 无法完成工作(如果我错了,请纠正我)。

所以我最终创建了自己的关系类型,到目前为止工作正常。这可能不是一个好的解决方案,但希望可以帮助你。

var LazyMany = Backbone.HasMany.extend({
  setRelated: function (related) {
    var relation = this.options
      , instance = this.instance
    ;

    if (related && !_.result(related, 'url')) {
      related.url = relation.relatedModel.prototype.urlRoot + 
        '?' + relation.reverseRelation.key + '=' + instance.id;
    }
    return LazyMany.__super__.setRelated.apply(this, arguments);
  }
});

然后在你的模型中:

var Album = Backbone.RelationalModel.extend({
  urlRoot: '/api/album/'
});

var Artist = Backbone.RelationalModel.extend({
  urlRoot: '/api/artist/',
  relations:[{
    key: 'albums',
    type: LazyMany,
    includeInJSON: false,
    relatedModel: Album,
    reverseRelation: {
      key: 'artist',
      // I didn't test this, I don't have artist_id, artist is "id" in my app
  keySource: 'artist_id',
  keyDestination: 'artist_id',
      includeInJSON: 'id'
    }
  }]
});

因此,如果您没有定义 collectionType 或者您的集合没有 url 字段,则 LazyMany 将使用 url: 创建一个集合/api/album/?artist=62351。然后你只需要获取集合:artist.get('albums').fetch()

希望这会有所帮助,我仍在寻找更好的解决方案。

于 2013-04-12T19:40:37.327 回答