Я переписываю старый API, для которого пытаюсь одновременно вставить несколько значений в базу данных MSSQL-Server (2008), используя модуль узла mssql .Теперь я способен сделать это каким-то образом , но я хочу следовать этим рекомендациям .Я провел свое исследование и перепробовал много вещей для достижения моей цели.Однако я не смог найти ни одного решения, которое бы работало правильно.
До
Вы можете удивиться:
Ну, вы переписываете этот API, поэтому должен быть способ, которым это было сделано раньше, и это работало?
Конечно, вы правы, он работал раньше, но ... не вКак я чувствую себя комфортно с использованием в переписать.Позвольте мне показать вам, как это было сделано раньше (добавлено немного абстракции, конечно):
const request = new sql.Request(connection);
let query = "INSERT INTO tbl (col1, col2, col3, col4) VALUES ";
for (/*basic for loop w/ counter variable i*/) {
query += "(1, @col2" + [i] + ", @col3" + [i] + ", (SELECT x FROM y WHERE z = @someParam" + [i] + "))";
// a check whether to add a comma or not
request.input("col2" + [i], sql.Int(), values[i]);
// ...
}
request.query(query, function(err, recordset) {
// ...
}
Пока это работает, опять же, я не совсем думаю, что это можно назвать чем-то вроде «Лучшая практика» .Также это показывает самую большую проблему: для выбора значения используется подвыбор.
То, что я пробовал до сих пор
Простой способ
Сначала я попробовал, вероятно, самую простую вещь:
// simplified
const sQuery = "INSERT INTO tbl (col1, col2, col3, col4) VALUES (1, @col2, @col3, (SELECT x FROM y WHERE z = @col4));";
oPool.request().then(oRequest => {
return oRequest
.input("col2", sql.Int(), aValues.map(oValue => oValue.col2))
.input("col3", sql.Int(), aValues.map(oValue => oValue.col3))
.input("col4", sql.Int(), aValues.map(oValue => oValue.col4))
.query(sQuery);
});
Я бы сказал, это было довольно хорошее предположение и на самом деле работало относительно хорошо.За исключением части, которая игнорирует каждый элемент после первого ... что делает его довольно бесполезным.Итак, я попытался ...
Request.multiple = true
... и подумал, что это сработает.Но - удивительно - это не так, все же только первый элемент вставлен.
Использование '?'для параметров
В этот момент я действительно приступил к поиску решения, поскольку вторым был только быстрый поиск в документации по модулям.Я наткнулся на этот ответ и попробовал его немедленно.Не потребовалось много времени, чтобы мой терминал выплыл
RequestError: Неверный синтаксис рядом с '?'.
Так много для этого.
Массовая вставка
Некоторые дальнейшие исследования привели к массовой вставке .Довольно интересная, классная функция и отличное обновление вопроса с решением по ОП!У меня были некоторые трудности с началом работы, но в итоге все выглядело действительно хорошо: было вставлено несколько записей, и значения казались нормальными.
Пока я не добавил подзапрос.Использование его в качестве значения для объявленного столбца не вызвало никакой ошибки, однако при проверке значений таблицы просто отображалось значение
0
для этого столбца.Совсем не большой сюрприз, но каждый может мечтать, верно?
Ленивый путь
Я действительно не знаю, что об этом думать:
// simplified
Promise.all(aValues.map(oValue => {
return oPool.request().then(oRequest =>
oRequest
.input("col2", sql.Int, oValue.col2)
.input("col3", sql.Int, oValue.col3)
.input("col4", sql.Int, oValue.col4)
.query(sQuery);
});
});
Он выполняет свою работу, но если какой-либо запрос завершается неудачей по какой-либо причине, другие, не прерывающиеся операции вставки, все равно будут выполняться, даже если это не будет возможным.
Lazy+ Транзакция
Поскольку продолжалось, даже если какой-то сбой был основной проблемой последнего метода, я попытался построить транзакцию вокруг него.Все запросы успешны?Хорошо, коммит.Любой запрос имеет ошибку?Ну, просто откат чем.Поэтому я создаю транзакцию, перенес в нее свою конструкцию Promise.all и попробовал снова.И в моем терминале появляется следующая ошибка:
TransactionError: Can't acquire connection for the request. There is another request in progress.
Если вы зашли так далеко, мне не нужно сообщать вам, в чем проблема.
Резюме
То, что я еще не пробовал (и не думаю, что попробую это), - это использование способа транзакции и последовательный вызов операторов.Я не верю, что это будет путь.
И я также не думаю, что следует использовать ленивый способ, поскольку он использует отдельные запросы для каждой записи для вставки, когда этоможно как-то сделать, используя только один запрос.Просто это как-то , я не знаю, сейчас не в моей голове.Поэтому, пожалуйста, если у вас есть что-нибудь, что может мне помочь, скажите мне.
Кроме того, если вы видите что-то еще, что не так с моим кодом, не стесняйтесь указать на это.Я не считаю себя новичком, но я также не думаю, что обучение когда-нибудь закончится.:)