我很好奇是否有办法更改模型上指定id
时使用的withRelated
?
情况如下:
我正在开发一个具有日历组件的平台,该日历需要支持定期约会。我不是创建定期约会的每个潜在实例,而是动态地生成这些重复,这导致更少的维护。我的Appointment
模型也具有与每个实例关联的关系。 Appointment
可以包含许多services
等。当使用withRelated
在数据库中存在的约会(不是动态生成)上加载这些关系时,id
约会被传递到withRelated
尝试加载和工作的任何关系。
但是,使用这些动态生成的约会,我实际上需要使用生成这些实例的父约会的id
来加载关系。不幸的是,我似乎无法找到一种方法来指定使用父id
或我可以拦截的地方并在加载关系之前更改它。
我的情况很奇怪,但如果我可以更改调用withRelated
时传入的内容,那将是一个简单的修复。
这可能吗?
我也愿意接受其他建议。
为了清楚起见,我的目标非常简单。当Bookshelf加载多对多关系时,它使用加入模型的idAttribute
来加载相关关系。
例如,Appointment
是我的主要模型,与Pets
具有多对多关系。因此,当我加载pets
关系时,Bookshelf会在appointment_pets
表上进行联接,以查找appointment_pet.appointment_id IN (?)
的所有记录,其中参数为id
来自{{1}表格。
我希望的目标是在查找这些关系时能够用appointment
替换appointment.id
,因为在我的情况下,这些动态记录实际上并不存在于数据库中,因此需要使用附加到父记录的信息,确实存在。
我终于能够通过暂时将模型上的appointment.parent_id
从id
更改为idAttribute
,将不同的id
注入上述查询中。查询是正确的,传递的参数也是正确的,但返回模型时关系为空。
parent_id
我看到以下调试输出:
// appointment model
pets() {
return this.belongsToMany('Pet', 'appointment_pet', 'parent_id');
},
},
// Returns all appointments
fetchAll(businessId, options) {
options = options || {};
// If a start and end date are passed, return all appointments
// within that range, with recurrences expanded.
if (!_.isUndefined(options.startDate) &&
!_.isUndefined(options.endDate)) {
const startDate = Moment(options.startDate);
const endDate = Moment(options.endDate);
// temporarily change id attribute so `parent_id` is used when looking up the relation
Appointment.prototype.idAttribute = 'parent_id';
return Appointment
.query((qb) => {
qb.from(Bookshelf.knex.raw('get_appointments(?, ?, ?) AS appointment', [businessId, startDate.toISOString(), endDate.toISOString()]));
})
.fetchAll({
withRelated: [{
pets: (qb) => {
qb.select(['appointment_id as parent_id', 'pet.*']);
}
}]
});
}
// Otherwise, return all appointments
return Appointment.findAll({ businessId: businessId }, options);
},
在postgres中运行此命令,我看到正确的输出,但仍然没有关系。我看到#1203并尝试将{ method: 'select',
options: {},
bindings:
[ null,
'35a2941c-d73f-4cf3-87de-bfbcbc92fbc5', <-- these are all `appointment.parent_id`
'5de28a57-ce4c-4fcc-865a-54cf97e08c6c',
'bf4b6784-b96a-4321-8335-e449aa8dcda1',
'695edc54-3a93-42a5-a3e0-b331f26912cf',
'76a99204-9659-4270-904c-2c42e5c40a15',
'28437e3c-abc1-4fd6-8c26-5543c09ab730',
'350da29d-0e82-4e6c-b9fe-be31c64655b4',
'bcaee041-c9ec-4a34-8c0d-8f21d2d79197',
'91380fcc-2f0d-4344-a24b-dc37abe3931f',
'31796797-5041-4fae-815b-0f2c368654b0',
'94800af3-fd23-4b59-af88-15b1f622e8e1',
'aa8c202d-249e-4ffc-ab55-e535f2c2121f',
'8a1fd093-45a6-4864-8c52-ea8851740f77',
'5f91ad6f-4231-4d18-b718-d99fcc17a18b',
'5f879e43-a44f-41dd-b9dd-11f06af4cc8d' ],
sql: 'select "pet".*, "appointment_pet"."parent_id" as "_pivot_parent_id", "appointment_pet"."pet_id" as "_pivot_pet_id" from "pet" inner join "appointment_pet" on "appointment_pet"."pet_id" = "pet"."id" where "appointment_pet"."parent_id" in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'}
明确添加到选择中,但仍然没有运气。
答案 0 :(得分:0)
很遗憾,我没有足够的数据来复制您的问题。我在一个基本的一对多示例上尝试过,我认为最简单的方法是在模型本身中定义一个新的关系。 E.g:
var Genre = bookshelf.Model.extend({
tableName: 'genres',
movie: function() {
return this.hasMany(Movie);
},
movie_parent: function() {
return this.hasMany(Movie, 'parent_id');
}
});
var Movie = bookshelf.Model.extend({
tableName: 'movies'
genre: function() {
return this.belongsTo(Genre);
},
genre_parent: function() {
return this.belongsTo(Genre, 'id');
}
});
那么,你可以在withRelated
属性中查询它相当简单。
new Movie().fetchAll({
withRelated: ['genre_parent'] //can be replaced with withRelated: ['genre']
}).then(function(movies) {
res.json(movies);
});
如果这不是您正在寻找的解决方案,请提供其他数据(数据库结构会很有趣)