问题描述
这是我第一次使用 tedious.js
,但我仍然不太了解.我主要在此处中浏览文件.
This is the first time I'm using tedious.js
, I still don't understand it a lot. I'm mostly going over their documentation here.
以下是POST方法中的逻辑.
Following is the logic in the POST method.
- 检查给定语句ID的标记是否已存在
- 如果标签存在,则将消息返回给客户端
- 如果标签不存在,则将标签插入数据库中.
这是我在 express.js
中添加内容的"post"方法
This is my post method in express.js
to add "tag"
// POST add tags
router.post('/tag', function(req, res){
// get the body
const data = req.body;
// sql query to check if the tag already exists for the given id or not.
let sql = `SELECT * FROM tags WHERE corporate_statement_link_id = @corporate_statement_link_id and name = @name FOR JSON PATH`;
// sql query to insert the tag in the database
let query = `INSERT INTO tags (corporate_statement_link_id, name) VALUES(@corporate_statement_link_id, @name)`;
console.log("Getting tags");
try {
console.log("Checking if the tag '", data.name, "' exists for ", data.corporate_statement_link_id,".");
//This is where I'm using the tedious to make connection to Azure database
var conn = sqldb.createConnection();
var request = sqldb.createRequest(sql, conn);
request.addParameter('corporate_statement_link_id', TYPES.Int, data.corporate_statement_link_id);
request.addParameter('name', TYPES.VarChar, data.name);
//=========>>>
// This is where I'm not so sure what's happening and if I can call it this way.
// The reason I'm trying this is because var "request" is always undefined since it's done async?. so, even though the tag exists in the database, the code below to add the tag still runs.
var result = sqldb.runQuery(request, conn, res, '{}').then(d => {
console.log(d);
});
// console.log("Result: ", result);
if(!request){
console.log('the tag already exists')
res.status(300).send("Tag already exist.");
} else {
console.log("Tag ",data.name, "doesn't exist.")
console.log("Creating tag");
// This is to add the tag to the database
conn = sqldb.createConnection();
request = sqldb.createRequest(query, conn);
request.addParameter('corporate_statement_link_id', TYPES.Int, data.corporate_statement_link_id);
request.addParameter('name', TYPES.VarChar, data.name);
result = sqldb.runQuery(request, conn, res, '{}');
console.log("Result: ", result);
return result;
}
} catch(err){
res.send(err);
}
Azure数据库连接
'use strict'
// function to create connection to the SQL database
function createConnection(){
var AzureConfig = {
authentication: {
options: {
userName: "username",
password: "password"
},
type: "default"
},
server: "server",
options: {
database: "database",
encrypt: true,
validateBulkLoadParameters: true
}
};
// create connection to the database
var Connection = require('tedious').Connection;
var connection = new Connection(AzureConfig);
return connection;
}// end create connection
// create query request
function createRequest(query, connection){
var Request = require('tedious').Request;
console.log("Creating new request");
var req = new Request(query, function(err, rowCount) {
if(err){
console.log(err);
output.write(err);
}
connection && connection.close();
});
console.log("Request created..");
return req;
}
// Running the query
function runQuery(query, connection, output, defaultContent){
var request = query;
if(typeof query == 'string'){
request = createRequest(query, connection);
}
console.log("It's not a query but a request..");
var empty = true;
request.on('row', function(columns){
console.log("Checking and running the row..");
if(empty){
console.log("Response fetched from SQL Database.");
empty = false;
}
console.log("Columns found: ", columns[0].value);
// console.log(output);
output.write(columns[0].value);
// console.log("returning data");
// data.push(columns[0].value);
});
request.on('done', function(rowCount, more, rows){
console.log("The request is done..");
console.log(rowCount, "rows returned");
// output.end();
_OnDone(empty, defaultContent, output);
});
request.on('doneProc', function(rowCount, more, rows){
console.log("The request procedure is done..");
_OnDone(empty, defaultContent, output);
console.log(rowCount, "rows returned");
// output.end();
});
console.log("Executing request");
executeRequest(request, connection);
}
function _OnDone(empty, defaultContent, output){
if(empty){
output.write(defaultContent);
console.log('No results from database - default content is returned.');
}
try{
console.log('Closing Http Response output.');
// console.log("Output: ", output);
output.end();
} catch(err){
// output.write(err);
console.error(err);
}
}
// execute request to pull the data
function executeRequest(request, connection){
console.log("checking the connection..");
connection.on('connect', function(err){
if(err){
console.log(err);
//output.write(err);
}
console.log("request executing...");
console.log("Request: ", request);
connection.execSql(request);
});
}
module.exports.createConnection = createConnection;
module.exports.createRequest = createRequest;
module.exports.executeRequest = executeRequest;
module.exports.runQuery = runQuery;
错误消息和输出
Checking and running the row..
Response fetched from SQL Database.
Columns found: [{"corporate_statement_link_id":3,"name":"black-lives-matter","id":11},{"corporate_statement_link_id":3,"name":"edi","id":12},{"corporate_statement_link_id":3,"name":"test","id":13},{"corporate_statement_link_id":3,"name":"test2","id":14},{"corporate_statement_link_id":3,"name":"test3","id":23},{"corporate_statement_link_id":3,"name":"test","id":24}]
The request procedure is done..
Closing Http Response output.
undefined rows returned
GET /api/v1/statements/tags/3 200 353.227 ms - -
Getting tags
Checking if the tag ' test4 ' exists for 3 .
Creating new request
Request created..
It's not a query but a request..
Executing request
checking the connection..
POST /api/v1/statements/tag 200 27.657 ms - 2
request executing...
Request: Request {
_events: [Object: null prototype] {
row: [Function],
done: [Function],
doneProc: [Function]
},
_eventsCount: 3,
_maxListeners: undefined,
sqlTextOrProcedure: 'SELECT * FROM tags WHERE corporate_statement_link_id = @corporate_statement_link_id and name = @name FOR JSON PATH',
parameters: [
{
type: [Object],
name: 'corporate_statement_link_id',
value: 3,
output: false,
length: undefined,
precision: undefined,
scale: undefined
},
{
type: [Object],
name: 'name',
value: 'test4',
output: false,
length: undefined,
precision: undefined,
scale: undefined
}
],
parametersByName: {
corporate_statement_link_id: {
type: [Object],
name: 'corporate_statement_link_id',
value: 3,
output: false,
length: undefined,
precision: undefined,
scale: undefined
},
name: {
type: [Object],
name: 'name',
value: 'test4',
output: false,
length: undefined,
precision: undefined,
scale: undefined
}
},
originalParameters: [],
preparing: false,
canceled: false,
paused: false,
userCallback: [Function],
handle: undefined,
error: undefined,
connection: undefined,
timeout: undefined,
rows: undefined,
rst: undefined,
rowCount: undefined,
callback: [Function],
[Symbol(kCapture)]: false
}
The request procedure is done..
No results from database - default content is returned.
Closing Http Response output.
undefined rows returned
events.js:292
throw er; // Unhandled 'error' event
^
Error [ERR_STREAM_WRITE_AFTER_END]: write after end
at write_ (_http_outgoing.js:629:17)
at ServerResponse.write (_http_outgoing.js:621:15)
at _OnDone (C:\Users\shresthas\source\repos\statement-rater-app\routes\azure-db.js:99:16)
at Request.<anonymous> (C:\Users\shresthas\source\repos\statement-rater-app\routes\azure-db.js:87:9)
at Request.emit (events.js:315:20)
at Request.emit (C:\Users\shresthas\source\repos\statement-rater-app\node_modules\tedious\lib\request.js:154:18)
at Parser.<anonymous> (C:\Users\shresthas\source\repos\statement-rater-app\node_modules\tedious\lib\connection.js:1323:19)
at Parser.emit (events.js:315:20)
at Parser.<anonymous> (C:\Users\shresthas\source\repos\statement-rater-app\node_modules\tedious\lib\token\token-stream-parser.js:35:14)
at Parser.emit (events.js:315:20)
Emitted 'error' event on ServerResponse instance at:
at writeAfterEndNT (_http_outgoing.js:684:7)
at processTicksAndRejections (internal/process/task_queues.js:85:21) {
code: 'ERR_STREAM_WRITE_AFTER_END'
}
如何解决这样的问题:找到标签后,它绕过insert语句返回到客户端,但是如果标签不存在,我想插入它,然后将标签发送给客户端?
How can I resolve such that when the tag is found, it returns to the client bypassing the insert statement, but if the tag doesn't exist, I want to insert it and then send the tag to the client?
推荐答案
在@ Mike'Pomax'Kamermans的大力帮助下,我得以重新查看我的代码并解决了我遇到的问题.非常感谢@ Mike'Pomax'Kamermans.您向我展示路径的方式极大地帮助了我理解问题-比单纯给出答案要好.
After the massive help from @Mike'Pomax'Kamermans I was able to revisit my codes and fix the issue I was having. Thank you so much @Mike'Pomax'Kamermans. Your way of showing me the path was massively helpful in helping me understand the problem - better than simply giving the answer.
另外,还要感谢@mauridb,他以一种凉爽,更好的方式编写了 SQL
查询,对我有很大帮助.
Also, another thanks goes to @mauridb who helped me a lot with a cool and better way to write the SQL
query.
这是我的 azure-sql.js
现在的样子:
'use strict'
// function to create connection to the SQL database
function createConnection(){
var AzureConfig = {
authentication: {
options: {
userName: "username",
password: "password"
},
type: "default"
},
server: "server",
options: {
database: "database",
encrypt: true,
validateBulkLoadParameters: true
}
};
// create connection to the database
var Connection = require('tedious').Connection;
var connection = new Connection(AzureConfig);
return connection;
}// end create connection
// function to configure request to be sent to the SQL server
function configureRequest(sql, conn, parameters){
var request = createRequest(sql, conn);
parameters.forEach(function(param){
request.addParameter(param.name, param.type, param.data);
});
return request;
}
// create query request
function createRequest(query, connection){
var Request = require('tedious').Request;
var req = new Request(query, function(err, rowCount) {
if(err){
console.log(err);
}
connection && connection.close();
});
return req;
}
// Running the query
function runQuery(query, connection, callback){
var request = query;
if(typeof query == 'string'){
request = createRequest(query, connection);
}
var values = '';
// the rows are returned as a json array. Since it's sent in a batch,
// different events are raised.
// So the values are concatenated to create a single JSON object
request.on('row', function(column) {
values += column[0].value;
});
// if anything specific needs to be done after the process is complete
request.on('done', function(rowCount, more, rows){
// check if the SQL Server returned anything
values = checkValues(values);
callback(values);
});
// if anything specific needs to be done after the stored procedure is complete
// however, if we use connection.execSql(), it emits doneProc instead of done.
request.on('doneProc', function(rowCount, more, rows){
// check if the SQL Server returned anything
values = checkValues(values);
callback(values);
});
try {
executeRequest(request, connection);
} catch(err){
throw err
}
// return the values parsed as JSON
// return JSON.parse(values);
return values;
}
// function to check values if the response from SQL Server is empty
function checkValues(values){
if (values === ''){
// needs to be set to null if the SQL Server return nothing.
// This is required to ensure JSON is correctly parsed.
values = null;
}
return values;
}
// execute request to pull the data
function executeRequest(request, connection){
connection.on('connect', function(err){
if(err){
console.log(err);
res.send(err);
}
connection.execSql(request);
});
}
module.exports.createConnection = createConnection;
module.exports.createRequest = createRequest;
module.exports.executeRequest = executeRequest;
module.exports.configureRequest = configureRequest;
module.exports.runQuery = runQuery;
此后,其他所有内容都放置到位.然后,我只需要更新 router
,以便它可以将数据返回给客户端.
After this, everything else fell in to place. Then, I simply had to update the router
so that it can return the data to the client.
// POST add tags
router.post('/tag', function(req, res){
const data = req.body;
let sql = `declare @result as table (id int, corporate_statement_link_id int, [name] nvarchar(50));
with cte as
(
select * from ( values (@corporate_statement_link_id, @name) ) as t(corporate_statement_link_id, [name])
)
insert into @result
select * from (
insert into dbo.tags (corporate_statement_link_id, [name])
output inserted.id, inserted.corporate_statement_link_id, inserted.name
select * from cte
where not exists (
select * from dbo.[tags] where corporate_statement_link_id = cte.corporate_statement_link_id and [name] = cte.[name]
)) r
select * from @result for json auto;`;
try {
var conn = sqldb.createConnection();
// var request = sqldb.createRequest(sql, conn);
var parameters = [
{
'name': 'corporate_statement_link_id',
'type': TYPES.Int,
'data': data.corporate_statement_link_id
},
{
'name': 'name',
'type': TYPES.NVarChar,
'data': data.name
}
]
var request = sqldb.configureRequest(sql, conn, parameters);
// using the query above, check if the tag already exists or not,
// and if
sqldb.runQuery(request, conn, (result, err) => {
if(err){
res.send(500).send(err);
}
// The query above checks if the tag exists or not and inserts if it is not
// If the data is already present in the database, then it'll return null.
// otherwise, it'll return the data that is inserted.
if(result === null){
res.status(409).send("The tag already exists");
} else {
res.send(JSON.parse(result));
}
});
} catch(err){
res.send(err);
}
});
这篇关于验证数据库中不存在数据后,如何使用tedious.js在Azure SQL中插入数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!