执行一批添加或更新:最有效的方法是什么,我哪里出错了
本文关键字:是什么 方法 错了 出错 有效 一批 添加 更新 执行 | 更新日期: 2023-09-27 18:33:31
让我完整地解释一下我的情况。
我有一个像 JavaScript 对象
[{"QuestionId":"1","AnswerId":"21","AnswerText":"34"},
{"QuestionId":"2","AnswerId":"22","AnswerText":"23"},...]
我需要使用它来插入或更新由
CREATE TABLE Answers (
id INT IDENTITY (1,1),
question_id INT NOT NULL,
partner_id UNIQUEIDENTIFIER NOT NULL,
val INT,
PRIMARY KEY (id),
FOREIGN KEY (question_id) REFERENCES Questions(id),
FOREIGN KEY (partner_id) REFERENCES Partners(id)
);
AJAX 调用是
var QAs = new Array();
$('.completeness.for-answer').each(function () {
QAs.push({
QuestionId : $(this).attr('data-qstnid'),
AnswerId : $(this).attr('data-answid'),
AnswerText : $(this).val(),
});
});
console.log(JSON.stringify(QAs));//TEST
$.ajax({
method: 'POST',
url: '/Answers/SubmitAnswers',
data : QAs,
success: function (retobj) {
console.log(retobj);
},
error: function () {
console.log("Error ...");
}
});
更新列表中的每一项,当它以执行存储过程的形式传输到数据库时
CREATE PROCEDURE AddOrUpdateAnswer
@AnswerId INT,
@AnswerVal INT,
@QuestionId INT,
@PartnerId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
IF EXISTS ( SELECT 1 FROM Answers WHERE id=@AnswerId )
UPDATE Answers SET val=@AnswerVal WHERE id=@AnswerId
ELSE
INSERT INTO Answers (question_id, partner_id, val) VALUES (@QuestionId, @PartnerId, @AnswerVal)
END
出现这种情况的原因是因为输入将采用 2 种形式中的 1 种:
-
@AnswerId
将被NULL
(输入对应于尚未提交的答案(,并将定义其他值。需要其他值来 -
@AnswerId
将是非NULL
的,其他值将被定义,尽管@PartnerId
和@QuestionId
与更新无关,因为该信息已在表关系中。
第一个问题:这是sproc
"添加或更新"的最有效方法吗?是否可以执行"添加或更新"以一次引入所有项目?因为,你看,我在每个项目上都调用这个。
我用来处理传入 JavaScript 对象的 AJAX 请求的控制器是
[HttpPost]
public ActionResult SubmitAnswers ( List<AnswerSubmission> Answers )
{
bool goodSoFar = true;
string status = "Answers submitted successfully";
try
{
this._Db.SubmitAnswers(Answers, this._Pid);
}
catch ( Exception e )
{
goodSoFar = false;
status = String.Format("Exception occured during answer submission: {0}", e.Message);
}
return Json(new { Succeeded = goodSoFar, Message = status } );
}
其中AnswerSubmission
由
public class AnswerSubmission
{
public int? AnswerId { get; set; }
public int? AnswerVal { get; set; }
public int QuestionId { get; set; }
}
函数SubmitAnswers
如下所示
public void SubmitAnswers ( List<AnswerSubmission> Answers, Guid PartnerId )
{
try
{
foreach ( AnswerSubmission A in Answers )
{
using ( SqlCommand cmd = new SqlCommand("AddOrUpdateAnswer", this._Conn) )
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@AnswerId", A.AnswerId);
cmd.Parameters.AddWithValue("@AnswerVal", A.AnswerVal);
cmd.Parameters.AddWithValue("@QuestionId", A.QuestionId);
cmd.Parameters.AddWithValue("@PartnerId", PartnerId);
this._Conn.Open();
cmd.ExecuteNonQuery();
this._Conn.Close();
}
}
} catch ( Exception ) { throw; }
}
第二个问题:这是正确的方法,对每个项目的连接进行Open
然后Close
?这似乎效率低下。有没有更好的方法?
第三个问题:如何调试这样的 AJAX 方法?我已经在控制器的各个地方设置了断点,但没有一个被命中。我在 JavaScript 的 success
函数返回的对象中看到的被抛出的异常说
"提交答案期间发生异常:未设置对象引用 到对象的实例。
但没有将我指向代码中的任何行。所以我不知道哪个对象引用没有设置为对象的实例。
这里非常感谢任何帮助。
-
SQL还不错,但可能会更好。您可能正在使用 MERGE 语句,该语句通常称为更新插入("更新或插入"(。但是,如果您要插入很多答案,我建议您使用表值参数 (TVP( 将所有记录一次性传递到 SQL Server。
-
通常,您的连接也会包装在
using
语句中,以便您适当地处理连接。从发布的代码中不清楚您可能如何处理这个问题。如果你打算使用 TVP,你肯定会重写循环。
如果它没有击中您的控制器, 则可能是您的路由错误并且您去了错误的位置,或者管道中的某些内容(添加的处理程序?(正在尝试执行某些操作(例如记录请求(,并且在它到达控制器之前失败了
A.我在您的代码中没有看到您传递@PartnerId
值的任何地方。AJAX
中的QAs
对象没有该部分。
回答您的问题:
-
您的
sproc
应该稍微改变以适应null
@AnswerId
。CREATE PROC AddOrUpdateAnswer { @PartnerId UNIQUEIDENTIFIER, @QuestionId INT, @AnswerId INT = NULL, @AnswerVal INT = NULL }
再往前...
IF EXISTS (SELECT Id FROM Answers WHERE Id = ISNULL(@AnswerId, -1))
-
将
this._Conn.Open()
和this._Conn.Close()
移到foreach
语句之外。 -
我发现很难调试 AJAX 调用,因为它们可能在不同的线程下运行。在 ajax 调用的输入方法 -/Answers/SubmitAnswers 上放置一个断点,然后创建一个简单的测试表单,您可以直接从视图中发布该表单以查看它是否有效。