首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

解決 SCOPE_IDENTITY() 返回值異常問題:新增資料後 ID 卻一直為 1 的排查思路

     編輯:程式設計綜合問答

在使用 ADO.NET 操作 SQL Server 時,開發者常透過 SCOPE_IDENTITY() 或 @@IDENTITY 取得剛插入資料的自增主鍵。然而有網友發現:無論新增幾次資料,回傳的 ID 永遠是 1,導致後續刪除、修改功能失效。經排查,問題核心在於資料存取層(DBHelper)的執行方法回傳值設計不當。

問題現場還原

使用者在 Windows Forms 專案中,透過 TreeView 顯示商品分類,右鍵選單提供「新增商品」、「刪除商品」、「修改」功能。新增程式碼如下:

private void 添加商品ToolStripMenuItem_Click(object sender, EventArgs e) {
    int id = DBHelper.cute("INSERT INTO Cards VALUES ('新商品') SELECT @@IDENTITY AS 'Identity'");
    if (id <= 0) { MessageBox.Show("新增失敗。"); return; }
    // 後續將 id 存入 TreeNode.Tag 供刪除/修改使用
    var node = treeView1.Nodes[0].Nodes.Add("新品牌");
    node.Tag = id;
    // ...
}

刪除時從 treeView1.SelectedNode.Tag 取得 ID 執行 DELETE,但發現 Tag 值始終為 1,導致找不到對應記錄。

根本原因分析

最佳回答一針見血指出:DBHelper.execute 回傳的是「影響行數」,而非 SELECT 的查詢結果。 程式碼中呼叫 DBHelper.cute(推測為 ExecuteScalar 封裝),若內部實際呼叫的是回傳影響行數的方法,則 INSERT 成功永遠回傳 1(影響 1 列),而非新生成的 Identity 值。

正確解決方案

  1. 確認 DBHelper 方法語意:ExecuteScalar 才能取得單一值(如 SCOPE_IDENTITY()),ExecuteNonQuery 只回傳影響行數。
  2. SQL 寫法建議:使用 SCOPE_IDENTITY() 而非 @@IDENTITY,避免觸發器導致取錯值。
    string sql = "INSERT INTO Cards (CardsName) VALUES ('新商品'); SELECT CAST(SCOPE_IDENTITY() AS INT);";
    int newId = (int)cmd.ExecuteScalar(); // 必須用 ExecuteScalar
    
  3. 參數化查詢:避免 SQL 注入,並正確處理字串逸出。

補充:為何第二次除錯卻正常?

使用者提到「再次除錯發現可以刪除了」,原因可能是:第一次執行時資料庫為空,Identity 從 1 開始;但程式邏輯錯誤導致 Tag 存成 1。第二次除錯時,資料庫已有資料,Identity 為 2、3…,但程式碼未改,Tag 仍會被存成 1(影響行數),只是恰好資料庫裡有 ID=1 的舊資料,刪除才「看似」成功。實際上仍是邏輯錯誤。

最佳實務總結

  • 新增資料需取回自增 ID 時,務必使用 ExecuteScalar + SCOPE_IDENTITY()。
  • 資料存取層應明確區分「查詢單一值」、「執行非查詢」、「查詢資料集」三類方法,命名語意清晰(如 GetScalar、ExecuteNonQuery、Query)。
  • 除錯時善用 SQL Profiler 或輸出實際 SQL,驗證資料庫端真正收到的指令。

掌握這些細節,即可避免「ID 永遠是 1」這類低級卻隱蔽的 Bug,讓資料操作更穩健可靠。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved