【问题标题】:Insert with relationships in AdonisJS with transaction使用事务在 AdonisJS 中插入关系
【发布时间】:2021-02-27 15:45:31
【问题描述】:

我是这个 JS Word 的新手,我阅读了 Adonis 和 Knex 文档,但我真的不明白我在这里做错了什么。

阿多尼斯:https://preview.adonisjs.com/guides/database/transactionshttps://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

我的模型:

Empresa 模型:

'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

【问题讨论】:

    标签: postgresql async-await transactions adonis.js


    【解决方案1】:

    您还需要传递交易引用来创建...

    只需在此处添加 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!
    

    更多信息在这里:https://adonisjs.com/docs/4.1/lucid#_transactions

    【讨论】:

    • 是的,我忘记了,我已经更改了一些原始代码(在帖子上更新)因为我无法使用 const empresa = await 获得值...需要将其放在响应获取值,现在我得到一个新错误(创建时将 trx 放在原始帖子的日志中)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-30
    • 1970-01-01
    • 2023-03-15
    • 2017-01-15
    • 1970-01-01
    相关资源
    最近更新 更多