基于密钥的骨干关系关系定义的正确方法

时间:2013-04-12 17:11:43

标签: javascript backbone.js backbone-relational

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

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

以规范的艺术家和专辑为例: 艺术家有很多专辑,由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失败了,我想对此有一个简明的答案。这可能有助于未来的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'
});

Bonus指向一个示例模型,该模型使用parent_id

引用其自相邻列表样式

2 个答案:

答案 0 :(得分:3)

所以,@ xzhang上面的方法让我继续研究这个问题。首先,我希望在这方面被证明是错误的,但我还没有找到一种方法,骨干关系处理这个问题而无需额外的自定义代码。因为在我看来这是OneToMany关系的一个令人难以置信的基本例子,我仍然抱有希望,我只是没有得到明显的东西。

这是我最终要做的事情来处理这种情况。不幸的是,当调用someobject.fetch('somerelationship')时,它仍然不会自动从服务器获取,这正是我真正想要的。对于大多数人来说,解析功能不是必需的,但是我正在呼叫的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()帮助器分配给setOptions。

 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')时自动提取子项的扩展只是票证,但我还没有发现如何在不修改骨干关系本身的情况下这样做。

答案 1 :(得分:0)

我正面临着确切的问题(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()

希望这可以提供帮助,我仍在寻找更好的解决方案。