Sequelize:使用 manyToMany 关联创建时避免重复
Sequelize: Avoid duplicates when create with manyToMany associations
我正在开发一个小型电子商务来销售电影票。我正在使用 Sequelize 来设计所有模型及其关联。我面临的问题与为创建最终订单而定义的路线有关:
Order.create({
userId: req.body.userId, // Number
sessionId: req.body.sessionId, // Number
seats: req.body.seats, // Array of objects
offsiteProducts: req.body.offsiteProducts // Array of objects
},
{
include: [
{
model: Seat,
attributes: ['area', 'number', 'roomId']
},
{
model: OffsiteProduct,
attributes: ['name', 'unitPrice']
}
]
}).then(order => {
res.json(order);
})
模型之间的关系如下:
User.hasMany(Order);
Order.belongsTo(User);
Session.hasMany(Order);
Order.belongsTo(Session);
Seat.belongsToMany(Order, { through: "reserved_seats" });
Order.belongsToMany(Seat, { through: "reserved_seats" });
OffsiteProduct.belongsToMany(Order, { through: ReservedOffsiteProduct });
Order.belongsToMany(OffsiteProduct, { through: ReservedOffsiteProduct });
对于“一对多”关系,传递外键足以让 Sequelize 正确关联模型。
但对于“多对多”关联(Sequelize 中的“belongsToMany”)它会重复 为席位输入的数据和场外产品,并将其创建为订单的一部分,并分别作为新的独立席位和场外产品创建。
如何避免这种行为并仅在最终订单中包含座位和场外产品数组?谢谢
执行此操作的一种方法是在事务中执行所有内容。这样,它将是原子的,即“全有或全无”。
Sequelize
为many-to-many associations提供了一些方法。在这种情况下,可以为每个联结点单独调用 table。
考虑到这一点,以下内容应该可以完成没有任何重复的插入:
let t = await sequelize.transaction()
try {
let order = await Order.create({
userId: req.body.userId,
sessionId: req.body.sessionId
}, {
transaction: t
})
let seats = await Seat.findAll({
where: {
id: {
[Op.in]: req.body.seatIds
}
}
})
let offsiteProducts = await OffsiteProducts.findAll({
where: {
id: {
[Op.in]: req.body.offsiteProductIds
}
}
})
await order.addSeats(seats, { transaction: t })
await order.addOffsiteProducts(offsiteProducts, { transaction: t })
await t.commit()
} catch (err) {
if (t) {
await t.rollback()
}
}
或者,如果 OffsiteProducts
和 Seats
table 中的行的主键是已知的,则上面的内容可以缩短为:
let t = await sequelize.transaction()
try {
let order = await Order.create({
userId: req.body.userId,
sessionId: req.body.sessionId
}, {
transaction: t
})
await order.addSeats(req.body.seatIds, { transaction: t })
await order.addOffsiteProducts(req.body.offsiteProductIds, { transaction: t })
await t.commit()
} catch (err) {
if (t) {
await t.rollback()
}
}
在文档 here.
中有更多关于将主键数组传递给 .addSeats
和 .addOffsiteProducts
方法的解释
我正在开发一个小型电子商务来销售电影票。我正在使用 Sequelize 来设计所有模型及其关联。我面临的问题与为创建最终订单而定义的路线有关:
Order.create({
userId: req.body.userId, // Number
sessionId: req.body.sessionId, // Number
seats: req.body.seats, // Array of objects
offsiteProducts: req.body.offsiteProducts // Array of objects
},
{
include: [
{
model: Seat,
attributes: ['area', 'number', 'roomId']
},
{
model: OffsiteProduct,
attributes: ['name', 'unitPrice']
}
]
}).then(order => {
res.json(order);
})
模型之间的关系如下:
User.hasMany(Order);
Order.belongsTo(User);
Session.hasMany(Order);
Order.belongsTo(Session);
Seat.belongsToMany(Order, { through: "reserved_seats" });
Order.belongsToMany(Seat, { through: "reserved_seats" });
OffsiteProduct.belongsToMany(Order, { through: ReservedOffsiteProduct });
Order.belongsToMany(OffsiteProduct, { through: ReservedOffsiteProduct });
对于“一对多”关系,传递外键足以让 Sequelize 正确关联模型。
但对于“多对多”关联(Sequelize 中的“belongsToMany”)它会重复 为席位输入的数据和场外产品,并将其创建为订单的一部分,并分别作为新的独立席位和场外产品创建。
如何避免这种行为并仅在最终订单中包含座位和场外产品数组?谢谢
执行此操作的一种方法是在事务中执行所有内容。这样,它将是原子的,即“全有或全无”。
Sequelize
为many-to-many associations提供了一些方法。在这种情况下,可以为每个联结点单独调用 table。
考虑到这一点,以下内容应该可以完成没有任何重复的插入:
let t = await sequelize.transaction()
try {
let order = await Order.create({
userId: req.body.userId,
sessionId: req.body.sessionId
}, {
transaction: t
})
let seats = await Seat.findAll({
where: {
id: {
[Op.in]: req.body.seatIds
}
}
})
let offsiteProducts = await OffsiteProducts.findAll({
where: {
id: {
[Op.in]: req.body.offsiteProductIds
}
}
})
await order.addSeats(seats, { transaction: t })
await order.addOffsiteProducts(offsiteProducts, { transaction: t })
await t.commit()
} catch (err) {
if (t) {
await t.rollback()
}
}
或者,如果 OffsiteProducts
和 Seats
table 中的行的主键是已知的,则上面的内容可以缩短为:
let t = await sequelize.transaction()
try {
let order = await Order.create({
userId: req.body.userId,
sessionId: req.body.sessionId
}, {
transaction: t
})
await order.addSeats(req.body.seatIds, { transaction: t })
await order.addOffsiteProducts(req.body.offsiteProductIds, { transaction: t })
await t.commit()
} catch (err) {
if (t) {
await t.rollback()
}
}
在文档 here.
中有更多关于将主键数组传递给.addSeats
和 .addOffsiteProducts
方法的解释