代码改变世界

NHibernate之旅(15):探索NHibernate中使用存储过程(上)

2008-11-03 11:05 by 李永京, ... 阅读, ... 评论, 收藏, 编辑

本节内容

  • 引入
  • 使用MyGeneration生成存储过程
  • 实例分析
    • 1.删除对象
  • 结语

引入

上一篇,我们介绍了视图,征集大家的意见,我接下来可能用三篇篇幅来介绍在NHibernate中如何使用存储过程的整个详细过程,这些全是在实际运用中积累的经验,涉及刚刚使用的错误信息,如何修改存储过程,并且比较没有使用存储过程的不同点,并非官方比较权威的资料,所以敬请参考。

使用MyGeneration生成存储过程

由于写存储过程不是这节的重点,我们来利用MyGeneration代码生成工具来利用为Customer表生成插入、更新、删除记录的存储过程。顺便也来学习MyGeneration开源的生成器怎么用的,如果你还没有,请到这里下载安装。

安装完之后,打开MyGeneration,如果你第一次使用MyGeneration会自动弹出“默认设置”对话框,需要你对MyGeneration设置数据库连接字符串、模板语言、数据库驱动、模板存放路径等信息,截图如下(由于这篇图片比较多,点击图片放大):

默认配置

我们要首先配置数据库连接字符串,如果你对手写感兴趣,你可以直接在文本框中修改具体字符串;如果你和我一样,就点击“OLEDB...”按钮利用界面配置连接字符串,点击按钮之后,出来“数据连接属性”对话框,中文的哦,MyGeneration直接调用SQL Server的配置对话框,按下面图示,填写自己的连接字符串信息:

数据连接属性

然后点击“确定”,这个对话框的连接信息将保存在“默认配置”对话框中,点击“Save”保存配置信息。

MyGeneration使用提示

如果你的操作系统是Windows Vista,请右击“以管理员身份运行”MyGeneration,这一点我还是比较郁闷的,弄了很久MyGeneration配置信息和模板保存失败,后来换成以管理员身份运行问题全部解决。

这时,MyGeneration主界面就打开了,点击工具栏的第三个按钮,打开“模板浏览器”窗口,截图如下:

模板浏览器

展开Microsoft SQL Server节点,找到“Script Insert/Update/Delete Procedures for SQL Server”模板,右击选择执行,我们利用这个模板为Customer表生成增删改存储过程。

执行Procedures

打开后,这个模板界面如下,选择输出路径和数据库表,这里我输入路径为桌面,选择Customer表,点击OK。截图如下:

配置生成存储过程

这时在桌面上生成sql_procs_Customer.sql文件,打开SQL Server Management Studio执行这个SQL脚本,展开NHibernateSample表下的存储过程,已经出来了三个存储过程,分别是CustomerDelete、CustomerInsert、CustomerUpdate。

存储过程

好了,我们使用MyGeneration生成存储过程,这个工作完成了,但是噩梦开始了......

实例分析

还是一步一步来,依次从删除对象、新建对象、更新对象、查询对象来介绍在NHibernate中如何使用存储过程的整个详细过程。在NHibernate的映射文件中,在Class元素中提供了<sql-delete>、<sql-insert>、<sql-update>元素用于删除、新建、更新对象,注意这三个元素顺序唯一,就是下图显示的顺序,在根元素提供了<sql-query>元素用来查询对象,下图显示在Class元素中的增删改存储过程元素。

映射元素

1.删除对象

这篇数据访问层中代码我们使用NHibernate之旅(6):探索NHibernate中的事务中的代码,测试代码在NHibernate之旅(5):探索Insert, Update, Delete操作中体现,无需任何改动。

Step1:为了比较,我们先执行DeleteCustomerTest()测试方法,没有使用存储过程下删除对象生成SQL语句如下:

DELETE FROM Customer WHERE CustomerId = @p0 AND Version = @p1; @p0 = '7', @p1 = '1'

Step2:修改映射文件添加存储过程,打开Customer.hbm.xml映射文件,在Class元素下添加<sql-delete>节点,调用CustomerDelete存储过程,CustomerDelete存储过程有一个CustomerId参数,这里用一个问号表示:

<sql-delete>exec CustomerDelete ?</sql-delete>

Step3:执行DeleteCustomerTest()测试方法,出现错误“NHibernate.StaleObjectStateException : Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [DomainModel.Entities.Customer#4]”,这个错误是存储过程写法错误,我们修改CustomerDelete存储过程,去掉SET NOCOUNT ON,代码片段如下:

ALTER PROCEDURE [dbo].[CustomerDelete]
(
    @CustomerId int
)
AS
    --SET NOCOUNT ON
    DELETE 
    FROM   [Customer]
    WHERE  
        [CustomerId] = @CustomerId
    RETURN @@Error

Step4:执行DeleteCustomerTest()测试成功,NHibernate生成语句如下:

exec CustomerDelete @p0; @p0 = '6', @p1 = '1'

恩,成功了,但是在看看存储过程,想想存储过程中写的SQL语句,和没有使用存储过程,NHibernate生成的SQL语句有些不同,显然没有顾及到版本控制问题,使用存储过程NHibernate生成语句无缘无故增加了一个参数@p1,我们来解决一下:

Step5:修改存储过程添加Version处理: 

ALTER PROCEDURE [dbo].[CustomerDelete]
(
    @CustomerId int,
    @Version int
)
AS
    DELETE 
    FROM   [Customer]
    WHERE  
    [CustomerId] = @CustomerId and [Version] = @Version
    RETURN @@Error

Step6:执行DeleteCustomerTest()测试,发生错误:“过程或函数 'CustomerDelete' 需要参数 '@Version',但未提供该参数。” 哦,原来映射文件参数数量没有改。

Step7:修改存储过程参数数量,打开映射文件在<sql-delete>中添加一个参数即添加“,?”

<sql-delete>exec CustomerDelete ?,?</sql-delete>

Step8:最后执行DeleteCustomerTest()测试成功,NHibernate生成SQL语句如下,和NHibernate没有使用存储过程一样了,考虑了版本控制问题,完全符合。OK!!

exec CustomerDelete @p0,@p1; @p0 = '8', @p1 = '1'

当然了,如果你不想使用存储过程,也可以直接在<sql-delete>中写SQL语句,像这样,照样用。

<sql-delete>DELETE FROM [Customer] WHERE [CustomerId] = ? and [Version] =?</sql-delete>

结语

这篇就说到这里了,主要学习怎么使用MyGeneration提供的模板创建存储过程和删除对象存储过程的使用,下篇继续创建、更新、查询对象存储过程的使用。

本系列链接:NHibernate之旅系列文章导航

NHibernate Q&A

下次继续分享NHibernate!