首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

NHibernate實戰(16):深入掌握存儲過程的新增與更新操作

     編輯:關於.NET

前言

承接上一篇關於刪除操作存儲過程的介紹,本文將詳細探討在 NHibernate 中如何使用存儲過程實現實體對象的新增與更新。所有內容均源自實際專案經驗,涵蓋錯誤排查、存儲過程修改技巧,以及與原生 NHibernate 操作的差異對比,供開發者參考借鑒。

實戰案例:使用存儲過程新增對象

步驟 1:基準測試——原生 NHibernate 新增

首先執行 CreateCustomerTest() 測試方法,觀察未使用存儲過程時 NHibernate 生成的 SQL 語句:

INSERT INTO Customer (Version, Firstname, Lastname) VALUES (@p0, @p1, @p2);
select SCOPE_IDENTITY(); @p0 = '1', @p1 = 'YJing', @p2 = 'Lee'

可以看到 NHibernate 使用 native 生成器策略,自動選擇 identity 模式由資料庫生成主鍵。

步驟 2:配置映射文件引入存儲過程

修改 Customer.hbm.xml,在 <class> 元素下添加 <sql-insert> 節點:

<sql-insert>exec CustomerInsert ?,?,?,?</sql-insert>

此處四個問號對應存儲過程的四個參數。

步驟 3:遭遇參數錯誤

執行測試報錯:

NHibernate.Exceptions.GenericADOException: could not insert... 參數化查詢 '(@p0 int,@p1 nvarchar(3),@p2 nvarchar(7),@p3 int)exec CustomerIn' 需要參數 '@p3',但未提供該參數

錯誤提示參數 @p3 缺失,經排查發現存儲過程參數順序與 NHibernate 預期不一致。

步驟 4:修正存儲過程參數順序

調整 CustomerInsert 存儲過程,移除 SET NOCOUNT ON 並重新排列參數,將輸出參數 @CustomerId 置於最後:

ALTER PROCEDURE [dbo].[CustomerInsert]
(
 @Version int,
 @Firstname nvarchar(50) = NULL,
 @Lastname nvarchar(50) = NULL,
 @CustomerId int = NULL OUTPUT
)
AS
INSERT INTO [Customer] ([Version], [Firstname], [Lastname])
VALUES (@Version, @Firstname, @Lastname)
SELECT @CustomerId = SCOPE_IDENTITY();
RETURN @@Error

步驟 5:生成器策略衝突分析

修改後測試仍失敗,核心原因在於主鍵生成策略衝突:

  • native (identity):NHibernate 預期由資料庫自動生成主鍵,不接受存儲過程返回的 SCOPE_IDENTITY()
  • 存儲過程邏輯:已在過程中通過 SCOPE_IDENTITY() 顯式賦值主鍵

此時有兩種解決方案:

  1. 修改存儲過程(推薦):移除主鍵賦值邏輯,配合 NHibernate 原生生成器
  2. 變更生成器類型:將映射文件中 <generator> 改為 increment,關閉 IDENTITY_INSERT,由存儲過程負責主鍵生成

步驟 6:採用 increment 策略驗證成功

修改映射文件生成器配置:

<generator class="increment"></generator>

再次執行測試,成功生成 SQL:

exec CustomerInsert @p0,@p1,@p2,@p3;
@p0 = '1', @p1 = 'YJing', @p2 = 'Lee' ,@p3 = '18'

常見錯誤總結表

生成器類型直接操作存儲過程操作解決方案
native正常缺少 @p3 參數改用 increment
incrementIDENTITY_INSERT OFF 時報錯Batch update returned unexpected row count移除 SET NOCOUNT ON

替代方案:內嵌 SQL 語句

若不願使用存儲過程,可直接在映射中編寫 SQL,效果等同:

<sql-insert>INSERT INTO Customer (Version, Firstname, Lastname) VALUES (?,?,?)</sql-insert>

注意:此方式同樣要求生成器為 increment。

實戰案例:使用存儲過程更新對象

步驟 1:基準測試——原生更新 SQL

執行 UpdateCustomerTest(),觀察原生 SQL 包含版本控制欄位:

UPDATE Customer SET Version = @p0, Firstname = @p1, Lastname = @p2
WHERE CustomerId = @p3 AND Version = @p4;
@p0 = '2', @p1 = 'YJingCnBlogs', @p2 = 'Lee', @p3 = '13', @p4 = '1'

步驟 2:配置更新存儲過程映射

在映射文件添加 <sql-update>:

<sql-update>exec CustomerUpdate ?,?,?,?</sql-update>

步驟 3:並發異常與 SET NOCOUNT ON 問題

執行報錯 Row was updated or deleted by another transaction,同刪除操作一樣,需移除存儲過程中的 SET NOCOUNT ON 以便 NHibernate 獲取受影響行數。

步驟 4:完善存儲過程支援版本控制

修改 CustomerUpdate 加入 @OldVersion 參數:

ALTER PROCEDURE [dbo].[CustomerUpdate]
(
 @Version int,
 @Firstname nvarchar(50) = NULL,
 @Lastname nvarchar(50) = NULL,
 @CustomerId int,
 @OldVersion int
)
AS
UPDATE [Customer]
SET [Version] = @Version, [Firstname] = @Firstname, [Lastname] = @Lastname
WHERE [CustomerId] = @CustomerId AND [Version] = @OldVersion
RETURN @@Error

步驟 5:映射參數數量同步

映射文件中 <sql-update> 增加第五個參數:

<sql-update>exec CustomerUpdate ?,?,?,?,?</sql-update>

步驟 6:驗證完美生成 SQL

測試通過,生成 SQL 精確對應版本控制邏輯:

exec CustomerUpdate @p0,@p1,@p2,@p3,@p4;
@p0 = '4', @p1 = 'YJingCnBlogsCnBlogs', @p2 = 'Lee', @p3 = '13', @p4 = '3'

內嵌 SQL 替代方案

<sql-update>UPDATE [Customer] SET [Version] = ?,[Firstname] = ?,[Lastname] = ?
WHERE [CustomerId] =? AND [Version] =?</sql-update>

結語

本文結合上篇內容,完整演示了 NHibernate 中存儲過程在刪除、新增、更新三大操作中的實戰應用與坑點規避。下一篇將介紹 <sql-query> 調用存儲過程進行查詢的靈活用法。

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