执行一批添加或更新:最有效的方法是什么,我哪里出错了

本文关键字:是什么 方法 错了 出错 有效 一批 添加 更新 执行 | 更新日期: 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 种:

  1. @AnswerId将被NULL(输入对应于尚未提交的答案(,并将定义其他值。需要其他值来
  2. @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 函数返回的对象中看到的被抛出的异常说

"提交答案期间发生异常:未设置对象引用 到对象的实例。

但没有将我指向代码中的任何行。所以我不知道哪个对象引用没有设置为对象的实例。

这里非常感谢任何帮助。

执行一批添加或更新:最有效的方法是什么,我哪里出错了

  1. SQL还不错,但可能会更好。您可能正在使用 MERGE 语句,该语句通常称为更新插入("更新或插入"(。但是,如果您要插入很多答案,我建议您使用表值参数 (TVP( 将所有记录一次性传递到 SQL Server。

  2. 通常,您的连接也会包装在 using 语句中,以便您适当地处理连接。从发布的代码中不清楚您可能如何处理这个问题。如果你打算使用 TVP,你肯定会重写循环。

  3. 如果它没有击中您的控制器,
  4. 则可能是您的路由错误并且您去了错误的位置,或者管道中的某些内容(添加的处理程序?(正在尝试执行某些操作(例如记录请求(,并且在它到达控制器之前失败了

A.我在您的代码中没有看到您传递@PartnerId值的任何地方。AJAX中的QAs对象没有该部分。

回答您的问题:

  1. 您的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))
    
  2. this._Conn.Open()this._Conn.Close()移到foreach语句之外。

  3. 我发现很难调试 AJAX 调用,因为它们可能在不同的线程下运行。在 ajax 调用的输入方法 -/Answers/SubmitAnswers 上放置一个断点,然后创建一个简单的测试表单,您可以直接从视图中发布该表单以查看它是否有效。