使用documentation中的示例,仅在第一次插入时一切正常。在第二次以后,将出现错误。
const Product = this.sequelize.define('Product', {
title: Sequelize.STRING
});
const Tag = this.sequelize.define('Tag', {
name: Sequelize.STRING,
unique: true
});
const ProductTag = this.sequelize.define('ProductTag', {
product_id: Sequelize.INTEGER,
tag_id: Sequelize.INTEGER
});
Product.belongsToMany(Tag, {through: 'ProductTag', as: 'tag'});
Tag.belongsToMany(Product, {through: 'ProductTag'});
第一次插入可以正常工作。
Product.create({
title: 'Chair',
tag: [
{ name: 'Alpha'},
{ name: 'Beta'}
]
}, {
include: [{
model: Tag,
as: 'tag'
}]
})
SQL日志
INSERT INTO "Product" ("id","title","created_at","updated_at") VALUES (DEFAULT,'Chair','2019-02-25 12:51:50.802 +00:00','2019-02-25 12:51:50.802 +00:00') RETURNING *;
INSERT INTO "Tag" ("id","name","created_at","updated_at") VALUES (DEFAULT,'Alpha','2019-02-25 12:51:51.061 +00:00','2019-02-25 12:51:51.061 +00:00') RETURNING *;
INSERT INTO "Tag" ("id","name","created_at","updated_at") VALUES (DEFAULT,'Beta','2019-02-25 12:51:51.061 +00:00','2019-02-25 12:51:51.061 +00:00') RETURNING *;
INSERT INTO "ProductTag" ("product_id","tag_id","created_at","updated_at") VALUES (1,1,'2019-02-25 12:51:51.068 +00:00','2019-02-25 12:51:51.068 +00:00') RETURNING *;
INSERT INTO "ProductTag" ("product_id","tag_id","created_at","updated_at") VALUES (1,2,'2019-02-25 12:51:51.072 +00:00','2019-02-25 12:51:51.072 +00:00') RETURNING *;
后续插入Product.create(...)
会产生错误SequelizeUniqueConstraintError
Key "(name)=(Alpha)" already exists.
如何制作标签,以便如果该标签已经存在,则使用现有标签的ID并忽略该错误?
答案 0 :(得分:0)
我的解决方案。
添加方法#include <QtWidgets>
class LineEditStyle: public QProxyStyle
{
Q_OBJECT
Q_PROPERTY(int cursorWidth READ cursorWidth WRITE setCursorWidth)
public:
using QProxyStyle::QProxyStyle;
int cursorWidth() const{
if(m_cursor_width < 0)
return baseStyle()->pixelMetric(PM_TextCursorWidth);
return pixelMetric(PM_TextCursorWidth);
}
void setCursorWidth(int cursorWidth){
m_cursor_width = cursorWidth;
}
int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override
{
if(metric == PM_TextCursorWidth)
if(m_cursor_width > 0)
return m_cursor_width;
return QProxyStyle::pixelMetric(metric, option, widget);
}
private:
int m_cursor_width = -1;
};
class LineEdit: public QLineEdit
{
Q_OBJECT
public:
LineEdit(QWidget *parent = nullptr):
QLineEdit(parent)
{
LineEditStyle *new_style = new LineEditStyle(style());
new_style->setCursorWidth(10);
setStyle(new_style);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LineEdit w;
w.show();
return a.exec();
}
#include "main.moc"
updateOrCreate
使用
Product.updateOrCreate = function (options) {
return this.findOrCreate(options).then(res => {
let [row, created] = res;
if (created) return [row, created];
return row.update(options.defaults, options.transaction)
.then(updated => [updated, created]);
})
};
Tag.updateOrCreate = function (options) {
return this.findOrCreate(options).then(res => {
let [row, created] = res;
if (created) return [row, created];
return row.update(options.defaults, options.transaction)
.then(updated => [updated, created]);
})
};
答案 1 :(得分:0)
bulkCreate
和 ignoreDuplicates: true
这可能很有趣。在 sequelize@6.5.1 sqlite3@5.0.2 上测试,这会产生一个 INSERT OR IGNORE INTO
。
请注意下面进一步讨论的 ID 缺失问题。
const assert = require('assert');
const path = require('path');
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize({
dialect: 'sqlite',
storage: 'tmp.' + path.basename(__filename) + '.sqlite',
define: {
timestamps: false
},
});
(async () => {
const Tag = sequelize.define('Tag', {
name: {
type: DataTypes.STRING,
unique: true,
},
});
await sequelize.sync({force: true})
await Tag.create({name: 't0'})
// Individual create does not have the option for some reason.
// Apparently you're just supposed to catch.
// https://github.com/sequelize/sequelize/issues/4513
//await Tag.create({name: 't0', ignoreDuplicates: true})
// SQLite: INSERT OR IGNORE INTO as desired.
// IDs may be missing here.
const tags = await Tag.bulkCreate(
[
{name: 't0'},
{name: 't1'},
{name: 't1'},
{name: 't2'},
],
{
ignoreDuplicates: true,
}
)
const tagsFound = await Tag.findAll({order: [['name', 'ASC']]})
assert.strictEqual(tagsFound[0].name, 't0')
assert.strictEqual(tagsFound[1].name, 't1')
assert.strictEqual(tagsFound[2].name, 't2')
assert.strictEqual(tagsFound.length, 3)
await sequelize.close();
})();
缺少 ID 问题
不幸的是,Tag.bulkCreate
的返回值不包含 SQLite 在 INSERT INTO
期间生成的 ID,但正如在:https://github.com/sequelize/sequelize/issues/11223#issuecomment-864185973
这打破了 OP 提到的从退货后立即为产品分配标签的用例,因为我们需要直通表的 ID。
我不确定它与 OPs findOrCreate
选项相比如何,但我认为之后再进行第二次查找会更快,在我的文章中,我选择了标签模型“更新模型”控制器:
await Promise.all([
req.app.get('sequelize').models.Tag.bulkCreate(
tagList.map((tag) => {return {name: tag}}),
{ignoreDuplicates: true}
).then(tags => {
// IDs may be missing from the above, so we have to do a find.
req.app.get('sequelize').models.Tag.findAll({
where: {name: tagList}
}).then(tags => {
return article.setTags(tags)
})
}),
article.save()
])