zoukankan      html  css  js  c++  java
  • [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:UsersWolfyDesktopCustomer”中就会生成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 int
    16 )
    17 AS
    18     SET NOCOUNT ON
    19 
    20     INSERT INTO [TB_Customer]
    21     (
    22         [CustomerID],
    23         [CustomerName],
    24         [CustomerAddress],
    25         [Version]
    26     )
    27     VALUES
    28     (
    29         @CustomerID,
    30         @CustomerName,
    31         @CustomerAddress,
    32         @Version
    33     )
    34 
    35     RETURN @@Error
    36 GO
    37 
    38 --|--------------------------------------------------------------------------------
    39 --| [TB_CustomerUpdate] - Update Procedure Script for TB_Customer
    40 --|--------------------------------------------------------------------------------
    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 GO
    43 
    44 CREATE PROCEDURE [dbo].[TB_CustomerUpdate]
    45 (
    46     @CustomerID uniqueidentifier,
    47     @CustomerName nvarchar(16) = NULL,
    48     @CustomerAddress nvarchar(128) = NULL,
    49     @Version int
    50 )
    51 AS
    52     SET NOCOUNT ON
    53     
    54     UPDATE [TB_Customer]
    55     SET
    56         [CustomerID] = @CustomerID,
    57         [CustomerName] = @CustomerName,
    58         [CustomerAddress] = @CustomerAddress,
    59         [Version] = @Version
    60     WHERE 
    61         [CustomerID] = @CustomerID
    62 
    63     RETURN @@Error
    64 GO
    65 
    66 --|--------------------------------------------------------------------------------
    67 --| [TB_CustomerDelete] - Update Procedure Script for TB_Customer
    68 --|--------------------------------------------------------------------------------
    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 GO
    71 
    72 CREATE PROCEDURE [dbo].[TB_CustomerDelete]
    73 (
    74     @CustomerID uniqueidentifier
    75 )
    76 AS
    77     SET NOCOUNT ON
    78 
    79     DELETE 
    80     FROM   [TB_Customer]
    81     WHERE  
    82         [CustomerID] = @CustomerID
    83 
    84     RETURN @@Error
    85 GO
    sql_procs_TB_Customer.sql

    我使用的是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 int
    15 )
    16 AS
    17     SET NOCOUNT ON
    18 
    19     INSERT INTO [TB_Customer]
    20     (
    21         [CustomerID],
    22         [CustomerName],
    23         [CustomerAddress],
    24         [Version]
    25     )
    26     VALUES
    27     (
    28         NEWID(),
    29         @CustomerName,
    30         @CustomerAddress,
    31         @Version
    32     )
    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                 try
    12                 {
    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] = @CustomerID
    12 
    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]=@Version
    13 
    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

  • 相关阅读:
    一、业务场景-随机生成患者姓名
    十一、python的高级语法与用法
    全排列小结
    LeetCode——150. Evaluate Reverse Polish Notation
    斐波那契数列算法小结
    LeetCode——14. Longest Common Prefix
    LeetCode——13. Roman to Integer
    LeetCode——12. Integer to Roman
    LeetCode——11. Container With Most Water
    LeetCode——10. Regular Expression Matching
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/4085314.html
Copyright © 2011-2022 走看看