程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> NHibernate之旅(17):探索NHibernate中使用存儲過程(下)

NHibernate之旅(17):探索NHibernate中使用存儲過程(下)

編輯:關於.NET

本節內容

引入

實例分析

拾遺

結語

引入

上兩篇,介紹使用MyGeneration提供的模板創建存儲過程和刪除對象、創建對象、更新對象整個詳細過程,這篇介紹如何利用<sql-query>做更多的事,在程序開發中,我們不僅僅只利用存儲過程增刪查改對象,我們還可以想執行任意的存儲過程,這不局限於某個對象,某個CURD操作,怎麼做呢?注意:本篇並非官方權威的資料,所以敬請參考。如果你還沒有學習NHibernate,請快速鏈接到NHibernate之旅系列文章導航。

實例分析

下面我用幾個例子來分析使用<sql-query>來執行存儲過程。

1.返回標量

Step1:存儲過程

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元素上編寫如下代碼:

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

Step3:數據訪問方法

在數據訪問層中,使用ISession接口提供的GetNamedQuery方法來調用帶命名的存儲過程,並傳遞一個整形參數。代碼如下:

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

Step4:測試方法

測試上面的方法,驗證其標量返回的結果是否與預期的一致。

[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之旅系列中關於存儲過程的內容就說到這裡吧,下篇開始看看如何使用代碼生成器。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved