Я работаю через свою первую транзакцию 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, как я и думал.
Примечание. На самом деле это сделано для работы с первым типом асинхронной / ожидающей транзакции. Но я до сих пор не могу понять, почему не работает метод транзакции.