【问题标题】:Proper method for backbone-relational relationship definitions based on keys基于键的骨干关系定义的正确方法
【发布时间】:2013-04-12 17:11:43
【问题描述】:

我已经阅读了很多次文档,但我仍然不清楚这方面的内容。我认为骨干关系完全有可能做一些它没有做的事情。

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

以规范的艺术家和专辑为例: 一位艺术家有许多专辑,由album.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 引用其自身邻接列表样式的示例模型

【问题讨论】:

    标签: javascript backbone.js backbone-relational


    【解决方案1】:

    所以,@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 子项的扩展只是门票,但我还没有发现如何在不修改骨干关系本身的情况下做到这一点。

    【讨论】:

      【解决方案2】:

      我正面临着确切的问题 (Backbone-relational hasmany best practices),经过 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()

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

      【讨论】:

      • 感谢@xzhang,我很高兴看到我不是唯一一个期望与骨干关系有所不同的人。我试过你的方法,它确实有效,但经过几次额外的迭代,我最终使用了一个变体。
      猜你喜欢
      • 2012-07-05
      • 1970-01-01
      • 2020-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多