在Bookshelf.js中,始终从相关模型获取数据

10
我希望baffle.where({id:1}).fetch()始终作为baffle模型的一部分获取typeName属性,而不需要每次显式从baffleType获取。
以下对我有效,但似乎withRelated会在直接获取baffle模型时加载关系,而不是通过关系加载:
let baffle = bookshelf.Model.extend({
    constructor: function() {
        bookshelf.Model.apply(this, arguments);

        this.on('fetching', function(model, attrs, options) {
            options.withRelated = options.withRelated || [];
            options.withRelated.push('type');           
        });
    },

    virtuals: {
        typeName: {
            get: function () {
                return this.related('type').attributes.typeName;
            }
        }
    },
    type: function () {
        return this.belongsTo(baffleType, 'type_id');
    }
});

let baffleType = bookshelf.Model.extend({});

如何正确地做到这一点?

2个回答

8

仓库问题与 Fetched 事件相关,但是 Fetching 事件正常工作 (v0.9.2)

例如,如果您有第三个模型,比如:

var Test = Bookshelf.model.extend({
   tableName : 'test',
   baffleField : function(){
       return this.belongsTo(baffle)
   } 
})

然后执行 Test.forge().fetch({ withRelated : ['baffleField']}),这将触发 baffle 上的 fetching 事件。但是,除非您通过明确告知,否则 ORM 不会包含 type(子相关模型)。

Test.forge().fetch({ withRelated : ['baffleField.type']})

然而,如果在检索N条记录时需要进行N次查询,请尽可能避免这种情况。

更新 1

我正在谈论与你在触发fetching事件时所做的相同事情。

fetch: function fetch(options) {
   var options = options || {}
   options.withRelated = options.withRelated || [];
   options.withRelated.push('type');    
    // Fetch uses all set attributes.
   return this._doFetch(this.attributes, options);
}

model.extend中。然而,正如您所看到的,这可能会在version更改时失败。

好的,关于“fetching”的点子很有价值,谢谢。那么,如果我想保持业务逻辑DRY并跳过所有fetch()调用中的{ withRelated: ... }部分,修改options.withRelated是唯一的选择吗?在应用程序的这个部分,性能并不是关键问题。 - Estus Flask
@estus 我认为是的。然而,我一直在使用 Sequelize,所以不能确定。另一种做相同事情的方式是 overriding(JS 不好的词)model.extend 中的 fetch 方法。然而,使用 fetching 事件更多地是使用 Bookshelf 的方式。重写一个方法是更加干净的方式,但它可能会在版本升级/降级时失败。 - Satyajeet
看起来当“baffle”被加载为关系时,触发了“fetching”,但没有加载任何嵌套关系,因此应在每个父模型中指定“fetching”。您能否添加一个覆盖“fetch”的示例?它应该像这样:fetch: function (...args) { return bookshelf.Model.prototype.fetch.bind(this)(...args) }吗? - Estus Flask
1
谢谢,看起来不错,我猜这就是为什么 _doFetch 存在的原因。 - Estus Flask

4
这个问题很老,但我还是要回答一下。我通过添加一个名为fetchFull的新函数来解决这个问题,使事情更加DRY。
let MyBaseModel = bookshelf.Model.extend({
  fetchFull: function() {
    let args;
    if (this.constructor.withRelated) {
      args = {withRelated: this.constructor.withRelated};
    }
    return this.fetch(args);
  },
};

let MyModel = MyBaseModel.extend({
    tableName: 'whatever',
  }, {
    withRelated: [
      'relation1',
      'relation1.related2'
    ]
  }
);

那么每当您进行查询时,您可以调用Model.fetchFull()来加载所有内容,或在您不想影响性能的情况下,仍然可以使用Model.fetch()


1
谢谢,永远不会太晚。 - Estus Flask

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接