如何使用 npgsql 中的参数在单个命令中更新多行中的列值?
How to update a column value in multiple rows, in a single command, using Parameters in npgsql?
所以我想做的是在用户返回时用新值更新 table 个答案和 edit/changes 个以前的答案。因此,问卷有大约 20 个问题,用户填写这些问题,然后将其保存在 Questionnaire_ResponseTable 中,如果他们返回并更改答案,我想更新 table。很简单。
棘手的部分是我想防止 SQL 注入,所以当我构建 "stmnt" 时,我将用户答案作为参数插入(以防他们试图做一些不正当的事情).问题是因为我试图在一个数据库命令中更新所有 20 行,我多次声明“:answer”。我发现 npgsql 对所有“:answer”一视同仁。因此,当我去修改数据库中的 20 行时,每行对应一个用户回答的问题。而不是获得 20 行和 20 个唯一答案,每一行最终都会更新为相同的答案。
我尝试使用 string.format 来执行类似“:answer{0}”的操作,以区分“:answer”,但确实有效并引发了异常。通过不使用参数来插入用户提供的答案,我已经让一切正常工作,所以我知道我的 posgresql 命令有效问题只是以安全的方式执行以防止注入。
public void UpdateAnswers(List<string> paramAnswers) {
List<string> answers = paramAnswers;
string stmnt = "UPDATE demographic_responses AS dr SET answer = c.answer FROM (values ";
string updateVals = "";
for (int i = 1; i <= answers.Count; i++) {
updateVals = updateVals + string.Format("("+"'"+((App)Application.Current).participantDM.id+"',"+ "'"+i+"'," + ":answer{0}),",i);
}
updateVals = updateVals.Substring(0, updateVals.Length-1);
stmnt = stmnt + updateVals + ") AS c(user_id, question_id, answer) WHERE c.question_id = dr.question_id AND c.user_id = dr.user_id";
using (NpgsqlConnection conn = PgConnection.GetConnection()) {
using (NpgsqlCommand cmd = new NpgsqlCommand(stmnt, conn)) {
for (int i = 0; i < answers.Count; i++) {
cmd.Parameters.Add(PgHelpers.ToNpgsqlParameter(DemographicResponseTable.Column.answer));
cmd.Parameters[i].Value = answers[i];
}
cmd.ExecuteNonQuery();
}
}
}
设置参数而不实际将其发送到数据库(例如使用 ExecuteNonQuery),就像您在代码中所做的那样,绝对没有任何作用;这不是 Npgsql 特定的行为,它是一般的 database/ADO.NET 行为。
为了帮助您理解,从概念上讲,参数与直接在 SQL 查询中插入您的值没有什么不同(当然,注入保护和性能优势除外)。
如果您试图通过不向数据库发送 X 查询来优化性能,请考虑将您的架构更改为具有包含多个答案的单行,其中对问题的回答表示为列而不是行。
Npgsql 当前不支持的另一个选项是在一个命令中发送多个 UPDATE SQL 语句,而不是对每个语句执行 ExecuteNonQuery(后者发送 SQL 并等待响应)。不幸的是,这目前与参数不兼容(但将在 Npgsql 的下一个主要版本中得到支持)。
所以我想做的是在用户返回时用新值更新 table 个答案和 edit/changes 个以前的答案。因此,问卷有大约 20 个问题,用户填写这些问题,然后将其保存在 Questionnaire_ResponseTable 中,如果他们返回并更改答案,我想更新 table。很简单。
棘手的部分是我想防止 SQL 注入,所以当我构建 "stmnt" 时,我将用户答案作为参数插入(以防他们试图做一些不正当的事情).问题是因为我试图在一个数据库命令中更新所有 20 行,我多次声明“:answer”。我发现 npgsql 对所有“:answer”一视同仁。因此,当我去修改数据库中的 20 行时,每行对应一个用户回答的问题。而不是获得 20 行和 20 个唯一答案,每一行最终都会更新为相同的答案。
我尝试使用 string.format 来执行类似“:answer{0}”的操作,以区分“:answer”,但确实有效并引发了异常。通过不使用参数来插入用户提供的答案,我已经让一切正常工作,所以我知道我的 posgresql 命令有效问题只是以安全的方式执行以防止注入。
public void UpdateAnswers(List<string> paramAnswers) {
List<string> answers = paramAnswers;
string stmnt = "UPDATE demographic_responses AS dr SET answer = c.answer FROM (values ";
string updateVals = "";
for (int i = 1; i <= answers.Count; i++) {
updateVals = updateVals + string.Format("("+"'"+((App)Application.Current).participantDM.id+"',"+ "'"+i+"'," + ":answer{0}),",i);
}
updateVals = updateVals.Substring(0, updateVals.Length-1);
stmnt = stmnt + updateVals + ") AS c(user_id, question_id, answer) WHERE c.question_id = dr.question_id AND c.user_id = dr.user_id";
using (NpgsqlConnection conn = PgConnection.GetConnection()) {
using (NpgsqlCommand cmd = new NpgsqlCommand(stmnt, conn)) {
for (int i = 0; i < answers.Count; i++) {
cmd.Parameters.Add(PgHelpers.ToNpgsqlParameter(DemographicResponseTable.Column.answer));
cmd.Parameters[i].Value = answers[i];
}
cmd.ExecuteNonQuery();
}
}
}
设置参数而不实际将其发送到数据库(例如使用 ExecuteNonQuery),就像您在代码中所做的那样,绝对没有任何作用;这不是 Npgsql 特定的行为,它是一般的 database/ADO.NET 行为。
为了帮助您理解,从概念上讲,参数与直接在 SQL 查询中插入您的值没有什么不同(当然,注入保护和性能优势除外)。
如果您试图通过不向数据库发送 X 查询来优化性能,请考虑将您的架构更改为具有包含多个答案的单行,其中对问题的回答表示为列而不是行。
Npgsql 当前不支持的另一个选项是在一个命令中发送多个 UPDATE SQL 语句,而不是对每个语句执行 ExecuteNonQuery(后者发送 SQL 并等待响应)。不幸的是,这目前与参数不兼容(但将在 Npgsql 的下一个主要版本中得到支持)。