postgresql - 使用事务在 AdonisJS 中插入关系
问题描述
我是这个 JS Word 的新手,我阅读了 Adonis 和 Knex 文档,但我真的不明白我在这里做错了什么。
阿多尼斯:https ://preview.adonisjs.com/guides/database/transactions和https://adonisjs.com/docs/4.1/lucid#_transactions
knex:http ://knexjs.org/#Transactions
在没有任何问题的情况下,所有数据都存储没有问题,但是当我提出错误只是为了测试事务时,我可以注意到“empresas”表有一条记录而其他表是空的,我想通过事务的 rollback() 函数,当发生错误时,所有表都需要为空。有人可以在这里启发我吗?使用:Adonis 和 postgres
这是我的迁移:
表empresas:
'use strict'
/** @type {import('@adonisjs/lucid/src/Schema')} */
const Schema = use('Schema')
class EmpresaSchema extends Schema {
up () {
this.create('empresas', (table) => {
table.increments()
table.text('codigo').notNullable()
table.text('tipo').notNullable()
table.text('origem').notNullable()
table.bigInteger('grupo_id').notNullable()
table.text('nome_fantasia')
table.text('razao_social')
table.timestamps()
})
}
down () {
this.drop('empresas')
}
}
module.exports = EmpresaSchema
表内容:
'use strict'
/** @type {import('@adonisjs/lucid/src/Schema')} */
const Schema = use('Schema')
class ContatosSchema extends Schema {
up () {
this.create('contatos', (table) => {
table.increments()
table
.integer('tipo_id')
.unsigned()
.notNullable()
.references('id')
.inTable('contato_tipos')
table.text('nome').notNullable()
table.text('dado').notNullable()
table.timestamps()
})
}
down () {
this.drop('contatos')
}
}
module.exports = ContatosSchema
表empresa_contatos:
'use strict'
/** @type {import('@adonisjs/lucid/src/Schema')} */
const Schema = use('Schema')
class EmpresaContatosSchema extends Schema {
up () {
this.create('empresa_contatos', (table) => {
table.increments()
table
.integer('empresa_id')
.unsigned()
.references('id')
.inTable('empresas')
.onUpdate('CASCADE')
.onDelete('CASCADE')
.index()
table
.integer('contato_id')
.unsigned()
.references('id')
.inTable('contatos')
.onUpdate('CASCADE')
.onDelete('CASCADE')
.index()
})
}
down () {
this.drop('empresa_contatos')
}
}
module.exports = EmpresaContatosSchema
我的模型:
企业模式:
'use strict'
/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
const Model = use('Model')
class Empresa extends Model {
contatos () {
return this.belongsToMany('App/Models/Contato').pivotTable('empresa_contatos')
}
}
module.exports = Empresa
联系型号:
'use strict'
/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
const Model = use('Model')
class Contato extends Model {
static get table () {
return 'contatos'
}
empresa () {
return this.belongsToMany('App/Models/Empresa').pivotTable('empresa_contatos')
}
}
module.exports = Contato
这是我的 EmpresaController 的一部分:
'use strict'
const Database = use('Database')
const Empresa = use('App/Models/Empresa')
const Contato = use('App/Models/Contato')
const Sequence = use('App/Controllers/Http/SequenceController')
class EmpresaController {
async customCreate ({ request, response, auth }) {
const trx = await Database.beginTransaction()
try {
const { enderecos, contatos, ...data } = request.all()
if (data.endereco.logradouro !== '') {
enderecos.push(data.endereco)
}
if (data.contato.nome !== '') {
contatos.push(data.contato)
}
const codigo = await Sequence.gerarNovoCodigoCliente(auth.user.grupo_id, trx)
let empresa = null
await Empresa.create({
codigo: codigo,
grupo_id: 1,
tipo: data.tipo,
origem: data.origem,
nome_fantasia: data.nome_fantasia,
razao_social: data.razao_social
}, trx)
.then(response => {
empresa = response
})
.catch(error => {
console.log('error empresa:')
console.log(error)
})
contatos.forEach(async contato => {
let novosContato = null
await Contato.create({
nome: contato.nome,
dado: contato.dado,
tipo_id: contato.tipo_contato.id
}, trx)
.then(response => {
novosContato = response
console.log('contato ok')
})
.catch(error => {
console.log('error contato:')
console.log(error)
})
await empresa.contatos().attach(novosContato.id, null, trx)
.then(response => {
console.log('attach ok')
})
.catch(error => {
console.log('error attach:')
console.log(error)
})
})
await trx.commit()
return response.ok(empresa)
} catch (error) {
await trx.rollback()
return response.badRequest(error.message)
}
}
}
module.exports = EmpresaController
我已经尝试将每个异步函数放在一个 const 上并使用 promise.all 方法解决所有问题,并遇到同样的问题,我真的不知道,但我猜“const empresa = await Empresa.create(...... .)" 正在提交事务并在它之后运行其他所有内容。
(编辑)日志:
error contato:
Error: Transaction query already complete, run with DEBUG=knex:tx for more info
at completedError (/app/node_modules/knex/lib/transaction.js:261:9)
at /app/node_modules/knex/lib/transaction.js:231:22
From previous event:
at Client_PG.trxClient.query (/app/node_modules/knex/lib/transaction.js:229:33)
at Runner.<anonymous> (/app/node_modules/knex/lib/runner.js:138:36)
From previous event:
at /app/node_modules/knex/lib/runner.js:47:21
at processImmediate (internal/timers.js:461:21)
From previous event:
at Runner.run (/app/node_modules/knex/lib/runner.js:33:30)
at Builder.Target.then (/app/node_modules/knex/lib/interface.js:23:43)
warning:
WARNING: Adonis has detected an unhandled promise rejection, which may
cause undesired behavior in production.
To stop this warning, use catch() on promises or wrap await
calls inside try/catch.
TypeError: Cannot read property 'id' of null
at /app/app/Controllers/Http/EmpresaController.js:165:54
解决方案
您还需要传递交易参考来创建...
只需在此处添加 trx:
const empresa = await Empresa.create({
codigo: codigo,
grupo_id: 1,
tipo: data.tipo,
origem: data.origem,
nome_fantasia: data.nome_fantasia,
razao_social: data.razao_social
}, trx) <-- adding trx to create!
推荐阅读
- javascript - Angular 如何读取插值?
- ruby-on-rails - 无法使用 sequel-rails gem 安装 rails active_storage
- json - 邮递员:UTC检查员
- javascript - 为node js后端开发逻辑
- firebase - Firebase 延迟函数执行
- amazon-web-services - 禁用 CloudWatch 以监控 Lambda 函数的日志
- c# - 执行 Code First 迁移时无法在 Visual Studio 2017 中加载文件或程序集“System.ComponentModel.DataAnnotations”
- apache-kafka - 在 Apache Storm 中以不同的螺栓发布多个主题数据
- jmeter - Http Request Sampler 中的 Jmeter 路径设置
- postgresql - Postgres 不完整的模式表使用 pg-dump 转储