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

Proper method for backbone-relational relationship definitions based on keys

本文关键字:定义 方法 于键 关系      更新时间:2023-09-26

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

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

以典型的艺术家和专辑为例:一个艺术家有许多专辑,由album.artist_id

定义

/api/artist/62351可能返回

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

同样/api/专辑吗?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?它一定只是键/键源/键目的地的一些排列,我还没有尝试,或者是一个问题,骨干关系没有试图解决,但我的文档搜索失败了,我认为一个简洁的答案可能会帮助未来的谷歌人。

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
的自邻接表样式。

所以,@xzhang的方法让我在这个问题上不断迭代。首先,我很想证明自己是错的,但我还没有找到一种方法,可以在不添加自定义代码的情况下,通过主干关系处理这个问题。因为在我看来,这是一个非常基本的一对多关系的例子,我仍然抱着希望,我只是没有得到一些明显的东西。

这是我最后处理这种情况的方法。不幸的是,当someobject.fetch(' somerrelationship ')被调用时,它仍然不会自动从服务器获取,这是我真正想要的。解析函数对于大多数人来说是不必要的,但是对于我正在调用的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天的研究和查看源代码,我不认为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()

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