探索NHibernate中使用存储过程(下)

转自:http://www.cnblogs.com/lyj/archive/2008/11/07/1328782.html

 

引入

上两篇,介绍使用MyGeneration提供的模板建立存储过程和删除对象、建立对象、更新对象整个详细过程,这篇介绍如何利用<sql-query>作更多的事,在程序开发中,咱们不单单只利用存储过程增删查改对象,咱们还能够想执行任意的存储过程,这不局限于某个对象,某个CURD操做,怎么作呢?注意:本篇并不是官方权威的资料,因此敬请参考。若是你尚未学习NHibernate,请快速连接到NHibernate之旅系列文章导航。html

实例分析

下面我用几个例子来分析使用<sql-query>来执行存储过程。sql

1.返回标量

Step1:存储过程session

CREATE PROCEDURE scalarSProcs
    @number int
AS
BEGIN
    SELECT @number as value, 'YJingLee' as name
END

这里模拟验证键/值对,按键查询名称。这里返回YJingLee。学习

Step2:映射文件测试

在映射文件中使用<sql-query>并定义<sql-query>查询的名称,使用<return-scalar>元素来指定返回的标量值,并指定字段的别名和类型。调用存储过程时,须要一个参数,这里用命名参数表示,这里打开Customer.hbm.xml在Class元素上编写以下代码:spa

<sql-query name="ScalarSProcs">
  <return-scalar column="value" type="int"/>
  <return-scalar column="name" type="string"/>
  exec scalarSProcs :number
</sql-query>

Step3:数据访问方法scala

在数据访问层中,使用ISession接口提供的GetNamedQuery方法来调用带命名的存储过程,并传递一个整形参数。代码以下:code

public IList ScalarStoredProcedure()
{
    return _session.GetNamedQuery("ScalarSProcs")
        .SetInt32("number", 22).List();
}

Step4:测试方法xml

测试上面的方法,验证其标量返回的结果是否与预期的一致。htm

[Test]
public void ScalarStoredProcedureTest()
{
    IList list = _sprocs.ScalarStoredProcedure();
    object[] o = (object[])list[0];
    Assert.AreEqual(o[0], 22);
    Assert.AreEqual(o[1], "YJingLee");
}

OK,测试成功,NHibernate生成SQL语句以下:

exec scalarSProcs @p0; @p0 = '22'

2.设置参数

Step1:存储过程

CREATE PROCEDURE paramSProcs
     @i int,
     @j int
AS
BEGIN
    SELECT @i as value, @j as value2
END

这里模拟一个存储过程,学习如何运用参数。

Step2:映射文件

带参数的存储过程,参数有两种写法,一种是使用“?”参数来表示:

<sql-query name="ParamSProcs">
  <return-scalar column="value" type="long"/>
  <return-scalar column="value2" type="long"/>
  exec paramSProcs ?, ?
</sql-query>

另一种是混合方式,使用“?”参数和命名参数表示:

<sql-query name="ParamSProcs">
  <return-scalar column="value" type="long" />
  <return-scalar column="value2" type="long" />
  exec paramSProcs ?, :second
</sql-query>

Step3:数据访问方法

在数据访问层中,咱们一样使用GetNamedQuery方法来调用命名的<sql-query>存储过程,须要传递两个参数,这里支持位置参数和命名参数,其方法以下所示:

public IList ParamStoredProcedure()
{
    return _session.GetNamedQuery("ParamSProcs")
        .SetInt64(0, 10L)
        .SetInt64(1, 20L)
        //或者.SetInt64("second", 20L)
        .List();
}

Step4:测试方法

编写一个测试用例测试上面的方法,OK!

[Test]
public void ParamStoredProcedureTest()
{
    IList list = _sprocs.ParamStoredProcedure();
    object[] o = (object[])list[0];
    Assert.AreEqual(o[0], 10L);
    Assert.AreEqual(o[1], 20L);
}

3.实体查询

Step1:存储过程

上面的查询都是返回标量值的,也就是返回是的“裸”数据。 我须要查询Customer实体对象,怎么办呢?编写一个存储过程按CustomerId查询Customer。

CREATE PROCEDURE [entitySProcs]
  @CustomerId int
AS
BEGIN
   SELECT * FROM [Customer]
   WHere [CustomerId] =@CustomerId
END

Step2:映射文件

经过命名查询来映射这个存储过程,使用return返回具体的实体类,使用<return-property>告诉NHibernate使用哪些属性值,容许咱们来选择如何引用字段以及属性。

<sql-query name="EntitySProcs">
  <return class="DomainModel.Entities.Customer,DomainModel">
    <return-property name="CustomerId" column="CustomerId"/>
    <return-property name ="Version" column="Version"/>
    <return-property name="Firstname" column="Firstname"/>
    <return-property name="Lastname" column="Lastname"/>
  </return>
  exec entitySProcs :customerId
</sql-query>

这很是奇怪,我使用这种方式测试不经过,晚上和Gray Zhang讨论这个问题,Gray Zhang使用这个方式运行成功,在个人机器上运行不成功,始终出现“NHibernate.ADOException : could not execute query [ exec entitySProcs ? ] Name:customerId - Value:1 [SQL: exec entitySProcs ?] ”问题,我换了一下方式,去掉<return-property>元素,像这样:

<sql-query name="EntitySProcs">
  <return class="DomainModel.Entities.Customer,DomainModel"/>
  exec entitySProcs :customerId
</sql-query>

Step3:数据访问方法

public Customer EntityStoredProcedure(int customerId)
{
    return _session.GetNamedQuery("EntitySProcs")
        .SetInt32("customerId",customerId)
        .UniqueResult<Customer>();
}

Step4:测试方法

[Test]
public void EntityStoredProcedureTest()
{
    Customer customer = _sprocs.EntityStoredProcedure(1);
    int customerId = customer.CustomerId;
    Assert.AreEqual(1, customerId);
}

Step5:返回实体属性

有个需求,我不想返回整个实体Customer,我想返回实体的Firstname属性怎么办呢?哦,反应过来了,使用返回标量的方法,我来写下<sql-query>:

<sql-query name="SingleEntitySProcs">
  <return-scalar column="Firstname" type="string" />
  exec singleEntitySProcs
</sql-query>

注意存储过程当前仅仅返回标量和实体。接下来就留给你们完成吧!给个提示,先写存储过程,而后写访问方法,最后测试一下看看是否返回的Firstname列表了。

拾遗

使用存储过程查询没法使用setFirstResult()/setMaxResults()进行分页。

存储过程的参数的位置顺序是很是重要,必须和NHibernate持久化类属性顺序相同。

你能够在存储过程里设定SET NOCOUNT ON,这可能会提升效率。

咱们能够在类映射里使用<loader query-ref="EntitySProcs"/>引用这个命名查询定制装载存储过程。

结语

好了,经过三篇文章的介绍,知道了如何在NHibernate使用存储过程来删除对象、建立对象、更新对象、查询对象等操做,还有一些零碎的东西就在于你们在平时学习中去探索了。NHibernate之旅系列中关于存储过程的内容就说到这里吧,下篇开始看看如何使用代码生成器。

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

NHibernate Q&A

下次继续分享NHibernate!

相关文章
相关标签/搜索