Почему выбрасывается моя транзакция knex: Ошибка ссылки: <table>не определена - PullRequest
0 голосов
/ 01 мая 2020

Я работаю через свою первую транзакцию knex, используя метод транзакции. Цель состоит в том, чтобы набор из трех операторов вставки атомарно сохранял данные входящей записи в трех таблицах. Для контекста - входящая запись представляет родительский объект с двумя дочерними отношениями 1: M - «материал имеет от 0 до многих свойств, а материал имеет от 0 до многих примечаний». Таким образом, у меня есть отношение материалов, отношение материал_произведения и отношение материал_ответы.

У меня есть версия метода, работающего вне транзакции. Но когда я попытался обернуть функциональность внутри транзакции, как указано в документации Knex - раздел «Транзакция» - в подразделе «Тот же пример, что и выше, с использованием другого подхода await / asyn c:», Я получаю ошибку ссылки, что первое дочернее отношение не определено. Кроме того, я получаю

UnhandledPromiseRejectionWarning: ReferenceError: trx не определено

Примечание: родительская таблица вставляется первой, и ошибка ссылки возникает при попытке вставьте в первую дочернюю таблицу: 'material_properties'.

Вот что сработало:

const materialRecord = {
            name: material.name,
            description: material.description ? material.description : null,
            user_id: userId
        }

/** 
 * Insert primary material into materials & get id value for FK
 */
const materialPrimaryKeyArray = await knex('materials')
  .returning('id')
  .insert(materialRecord)
  .catch(error => console.error(`Unable to persist record, ${error}`)) 
const materialPrimaryKey = materialPrimaryKeyArray[0];

/**
 * Persist properties and/or notes if they exist
 */
if (material.materialProperties) {
  material.materialProperties.forEach(property => {
    property['material_id'] = materialPrimaryKey
  });
  knex('material_properties')
    .returning('id')
    .insert(material.materialProperties)
    .catch(error => console.error(`Unable to persist record, ${error}`)) 
};

if (material.materialNotes) {
  material.materialNotes.forEach(note => {
    note['material_id'] = materialPrimaryKey
  });
  knex('material_notes')
    .returning('id')
    .insert(material.materialNotes)
    .catch(error => console.error(`Unable to persist record, ${error}`)) 
   };
   
return materialPrimaryKey;

Вот что не работает:

try {
  const materialRecord = {
    name: material.name,
    description: material.description ? material.description : null,
    user_id: userId
  }

  await knex.transaction(async trx => {
    const materialPrimaryKeyArray = await knex('materials')
      .insert(materialRecord, 'id')
      .transacting(trx)
    const materialPrimaryKey = materialPrimaryKeyArray[0];

    if (material.materialProperties && material.materialProperties.length > 0) {
      material.materialProperties.forEach(property => {
        property['material_id'] = materialPrimaryKey
      })

      const propertyInserts = await knex('material_properties')
        .insert(material.materialProperties, 'id')
        .transacting(trx)
      console.log(material_properties.length + ' properties attempted to save - ' + propertyInserts.length + ' properties successfully saved.')
    };

    if (material.materialNotes && material.materialNotes.length > 0) {
      material.materialNotes.forEach(note => {
        note['material_id'] = materialPrimaryKey
      })

      const noteInserts = await knex('material_notes')
        .insert(material.materialNotes, 'id')
        .transacting(trx)
      console.log(material_notes.length + ' properties attempted to save - ' + noteInserts.length + ' notes successfully saved.')
    };

    console.log('The material is successfully saved.')
  })

  return materialPrimaryKey;
} catch (error) {
  console.error(`Unable to persist data, ${error}`)
  trx.rollback
}

Имя таблицы такое же, как вы можете видеть в присваивании "propertyInserts".

Я пытался обещать каждую вставку, добавляя .catch между методами вставки и транзакции:

            const materialPrimaryKeyArray = await knex('materials')
                .insert(materialRecord, 'id')
                .catch(error => `Cannot persist record, ${error}`)
                .transacting(trx)
            const materialPrimaryKey = materialPrimaryKeyArray[0];

. Когда я сделал это, ReferenceError для таблицы (material_properties) исчезло и было заменено на

TypeError: (0, _connection.default) (...). Insert (... ) .catch (...). Транзакция не является функцией

Я также попытался переместить оператор catch ниже оператора транзакции. Это не дало приведенной выше ошибки TypeError, но также не исправило предупреждение UnhandledPromiseRejectionWarning, как я и думал.

Примечание. На самом деле это сделано для работы с первым типом асинхронной / ожидающей транзакции. Но я до сих пор не могу понять, почему не работает метод транзакции.

1 Ответ

1 голос
/ 04 мая 2020

Вы пытаетесь получить доступ к переменной trx вне ее области действия.

} catch (error) {
  console.error(`Unable to persist data, ${error}`)
  trx.rollback // here you are trying to use undefined variable
}

Вы можете просто удалить эту строку. Так как knex.transaction(async trx => {}) выдал ошибку, транзакция автоматически откатывается (потому что функция-обработчик перезапускает обещание).

Также простой доступ к функции без ее вызова не имел бы никакого значения trx.rollback и trx.rollback() не делает то же самое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...