首页 > 代码库 > [NHibernate]存储过程的使用(一)
[NHibernate]存储过程的使用(一)
目录
写在前面
文档与系列文章
Nhibernate中使用存储过程
一个例子
总结
写在前面
上篇文章一个小插曲,分析了延迟加载是如何解决N+1 select查询问题的。这篇开始介绍在nhibernate中如何使用存储过程,同时也介绍如何使用代码生成器,提高开发效率。
文档与系列文章
[Nhibernate]体系结构
[NHibernate]ISessionFactory配置
[NHibernate]持久化类(Persistent Classes)
[NHibernate]O/R Mapping基础
[NHibernate]集合类(Collections)映射
[NHibernate]关联映射
[NHibernate]Parent/Child
[NHibernate]缓存(NHibernate.Caches)
[NHibernate]NHibernate.Tool.hbm2net
[NHibernate]Nullables
[NHibernate]Nhibernate如何映射sqlserver中image字段
[NHibernate]基本配置与测试
[NHibernate]HQL查询
[NHibernate]条件查询Criteria Query
[NHibernate]增删改操作
[NHibernate]事务
[NHibernate]并发控制
[NHibernate]组件之依赖对象
[NHibernate]一对多关系(级联删除,级联添加)
[NHibernate]一对多关系(关联查询)
[NHibernate]多对多关系(关联查询)
[NHibernate]延迟加载
[NHibernate]立即加载
[NHibernate]视图处理
[NHibernate]N+1 Select查询问题分析
Nhibernate中使用存储过程
这里使用MyGeneration Code来生成针对TB_Customer数据表的增删改的存储过程。MyGeneration Code是一款开源的代码生成器,下载地址MyGeneration Code。
安装完成后,打开MyGeneration,如果第一次使用MyGeneration会自动弹出“默认设置”对话框,需要你对MyGeneration设置数据库连接字符串、模板语言、数据库驱动、模板存放路径等信息。
然后选择“save”对默认配置进行保存。然后MyGenration主界面就会弹出。如图
展开Microsoft SQL Server节点,找到“Script Insert/Update/Delete Procedures for SQL Server”模板,右击选择执行,我们利用这个模板为Customer表生成增删改存储过程。
打开后,这个模板界面如下,选择输出路径和数据库表,这里我输入路径为桌面,选择TB_Customer表,点击OK。截图如下:
此时在桌面“C:\Users\Wolfy\Desktop\Customer”中就会生成sql_procs_TB_Customer.sql文件,打开数据库,然后执行该文件中的sql脚本。
1 USE [Shop] 2 GO 3 4 --|-------------------------------------------------------------------------------- 5 --| [TB_CustomerInsert] - Insert Procedure Script for TB_Customer 6 --|-------------------------------------------------------------------------------- 7 IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id (N‘[dbo].[TB_CustomerInsert]‘) AND OBJECTPROPERTY(id, N‘IsProcedure‘) = 1) DROP PROCEDURE [dbo].[TB_CustomerInsert] 8 GO 9 10 CREATE PROCEDURE [dbo].[TB_CustomerInsert]11 (12 @CustomerID uniqueidentifier = NEWID() OUTPUT,13 @CustomerName nvarchar(16) = NULL,14 @CustomerAddress nvarchar(128) = NULL,15 @Version int16 )17 AS18 SET NOCOUNT ON19 20 INSERT INTO [TB_Customer]21 (22 [CustomerID],23 [CustomerName],24 [CustomerAddress],25 [Version]26 )27 VALUES28 (29 @CustomerID,30 @CustomerName,31 @CustomerAddress,32 @Version33 )34 35 RETURN @@Error36 GO37 38 --|--------------------------------------------------------------------------------39 --| [TB_CustomerUpdate] - Update Procedure Script for TB_Customer40 --|--------------------------------------------------------------------------------41 IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id (N‘[dbo].[TB_CustomerUpdate]‘) AND OBJECTPROPERTY(id, N‘IsProcedure‘) = 1) DROP PROCEDURE [dbo].[TB_CustomerUpdate]42 GO43 44 CREATE PROCEDURE [dbo].[TB_CustomerUpdate]45 (46 @CustomerID uniqueidentifier,47 @CustomerName nvarchar(16) = NULL,48 @CustomerAddress nvarchar(128) = NULL,49 @Version int50 )51 AS52 SET NOCOUNT ON53 54 UPDATE [TB_Customer]55 SET56 [CustomerID] = @CustomerID,57 [CustomerName] = @CustomerName,58 [CustomerAddress] = @CustomerAddress,59 [Version] = @Version60 WHERE 61 [CustomerID] = @CustomerID62 63 RETURN @@Error64 GO65 66 --|--------------------------------------------------------------------------------67 --| [TB_CustomerDelete] - Update Procedure Script for TB_Customer68 --|--------------------------------------------------------------------------------69 IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id (N‘[dbo].[TB_CustomerDelete]‘) AND OBJECTPROPERTY(id, N‘IsProcedure‘) = 1) DROP PROCEDURE [dbo].[TB_CustomerDelete]70 GO71 72 CREATE PROCEDURE [dbo].[TB_CustomerDelete]73 (74 @CustomerID uniqueidentifier75 )76 AS77 SET NOCOUNT ON78 79 DELETE 80 FROM [TB_Customer]81 WHERE 82 [CustomerID] = @CustomerID83 84 RETURN @@Error85 GO
我使用的是sql server2012的版本,在执行脚本的时候,生成添加Customer的存储过程,有问题
将NewId()函数去掉。修改后的存储过程
1 USE [Shop] 2 GO 3 --|-------------------------------------------------------------------------------- 4 --| [TB_CustomerInsert] - Insert Procedure Script for TB_Customer 5 --|-------------------------------------------------------------------------------- 6 IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id (N‘[dbo].[TB_CustomerInsert]‘) AND OBJECTPROPERTY(id, N‘IsProcedure‘) = 1) DROP PROCEDURE [dbo].[TB_CustomerInsert] 7 GO 8 9 CREATE PROCEDURE [dbo].[TB_CustomerInsert]10 (11 @CustomerID uniqueidentifier OUTPUT,12 @CustomerName nvarchar(16) = NULL,13 @CustomerAddress nvarchar(128) = NULL,14 @Version int15 )16 AS17 SET NOCOUNT ON18 19 INSERT INTO [TB_Customer]20 (21 [CustomerID],22 [CustomerName],23 [CustomerAddress],24 [Version]25 )26 VALUES27 (28 NEWID(),29 @CustomerName,30 @CustomerAddress,31 @Version32 )33 34 RETURN @@Error
生成的存储过程如下:
一个例子
在NHibernate的映射文件中,在Class元素中提供了<sql-delete>、<sql-insert>、<sql-update>元素用于删除、新建、更新对象,注意这三个元素顺序唯一,就是下图显示的顺序,在根元素提供了<sql-query>元素用来查询对象,下图显示在Class元素中的增删改存储过程元素。
删除对象
修改映射文件添加存储过程,打开Customer.hbm.xml映射文件,在Class元素下添加<sql-delete>节点,调用TB_CustomerDelete存储过程,TB_CustomerDelete存储过程有一个CustomerID参数,这里用一个问号表示:
<!--存储过程,check参数:none/rowcount/param--> <sql-delete>exec TB_CustomerDelete ?</sql-delete>
测试
1 /// <summary> 2 /// 通过存储过程方式删除客户信息 3 /// </summary> 4 /// <param name="customer"></param> 5 /// <returns></returns> 6 public bool DeleteCustomerByIDWithProcedure(Customer customer) 7 { 8 var session = NHibernateHelper.GetSession(); 9 using (ITransaction trans = session.BeginTransaction())10 {11 try12 {13 session.Delete(customer);14 session.Flush();15 trans.Commit();16 return true;17 }18 catch (Exception)19 {20 trans.Rollback();21 throw;22 }23 }24 }
此时会有一个异常“Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Wolfy.Shop.Domain.Entities.Customer#b0720295-9541-40b3-9994-610066224db8]”。这个错误是存储过程写法错误,我们修改TB_CustomerDelete存储过程,去掉SET NOCOUNT ON,代码片段如下:
1 ALTER PROCEDURE [dbo].[TB_CustomerDelete] 2 ( 3 @CustomerID uniqueidentifier 4 ) 5 AS 6 --SET NOCOUNT ON 7 8 DELETE 9 FROM [TB_Customer]10 WHERE 11 [CustomerID] = @CustomerID12 13 RETURN @@Error
再次运行进行测试,测试成功,查看生成的sql语句
你会发现在sql语句里面多了一个@p1的参数。这个参数为之前添加的Version参数,nhibernate中乐观并发控制添加的。
如何解决?
修改存储过程,将版本号添加上。
1 ALTER PROCEDURE [dbo].[TB_CustomerDelete] 2 ( 3 @CustomerID uniqueidentifier, 4 @Version int 5 ) 6 AS 7 --SET NOCOUNT ON 8 9 DELETE 10 FROM [TB_Customer]11 WHERE 12 [CustomerID] = @CustomerID and [Version]=@Version13 14 RETURN @@Error
不要忘了,此时的存储过程有两个参数了,版本号在映射文件中已经处理了,存储过程中已经帮咱们自动添加上了,如果是其他的参数可在映射文件通过"?,?..."添加多个参数。
<!--存储过程,check参数:none/rowcount/param--> <sql-delete check="rowcount" >exec TB_CustomerDelete ?</sql-delete>
再次运行进行测试,成功,生成的sql语句
exec sp_executesql N‘exec TB_CustomerDelete @p0‘,N‘@p0 uniqueidentifier,@p1 int‘,@p0=‘3727A133-C079-4DF9-B31E-7625B03F95DF‘,@p1=1
当然了,如果你不想使用存储过程,也可以直接在<sql-delete>中写SQL语句,像这样,照样用。
<sql-delete>DELETE FROM [TB_Customer] WHERE [CustomerID] = ? and [Version] =?</sql-delete>
生成的sql语句为
exec sp_executesql N‘DELETE FROM [TB_Customer] WHERE [CustomerID] = @p0 and [Version] =@p1‘,N‘@p0 uniqueidentifier,@p1 int‘,@p0=‘64C35DEE-84D9-4C2D-ABAF-7D53631E3EAA‘,@p1=1
总结
这篇文章主要介绍了代码生成器的简单使用及nhibernate中使用存储过程删除数据的过程。
参考文章:http://www.cnblogs.com/lyj/archive/2008/11/03/1325291.html
[NHibernate]存储过程的使用(一)