本來打算主鍵ID用觸發器產生,因為程式只需要一次IO就能插入一條資料。
圖在下面,這裡assigned不能改為native,從配置中看,是程式來產生ID,但實際oracle接受到插入訊息後,觸發器自動用序列替換了ID,因此遇到一個問題,就是程式不能擷取到剛才插入的實體的主鍵ID,於是改為設定檔中指定序列建立ID,為了看它產生的sql和串連資料庫的IO次數,我用NHibernateProfiler和sql server profiler進行了檢測,oracle沒找到好的檢測串連sql的工具,因此用mssql的偵查工具檢測了下。用NHibernateProfiler檢測產生sql時,迷惑了我,由於一系列的執行我共用了session,該工具都只顯示一個session,並且列出它產生了哪些sql,讓我以為它只是一個IO就把整個查詢和操作弄好了,nhibernate的預設延時載入好像是如果同一個session中沒有相同對象,然後從資料庫擷取對象,但該對象內部的其他對象會延時載入,並且他檢測出的sql,並不是真正資料庫擷取到查詢sql,比如查詢都參數化了,但NHibernateProfiler沒有很細的說明查詢的值是什麼參數,這在我查詢序列的建立和傳遞給插入實體物件的sql時沒看明白,我用sql server profiler才證實這點。
設定檔如下:
TestSeq.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel">
<class name ="DomainModel.Entities.TestSeq,DomainModel" table="TESTSeq">
<id name="ID" column="ID" type="int">
<generator class ="assigned"></generator>
</id>
<property name="NAME" column="NAME" type="string"/>
</class>
</hibernate-mapping>
該為指定序列產生ID後的設定檔如下:
TestSeq.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel">
<class name ="DomainModel.Entities.TestSeq,DomainModel" table="TESTSeq">
<id name="ID" column="ID" type="int">
<generator class="sequence">
<param name="sequence">TestSeq1</param>
</generator>
</id>
<property name="NAME" column="NAME" type="string"/>
</class>
</hibernate-mapping>
程式c#代碼執行資料庫語句如下:
var c = domainService.AddTestSeq(new DomainModel.Entities.TestSeq() { NAME = DateTime.Now.ToString() });
var a = domainService.GetTestById("002");
var b = domainService.GetTestById("003");
用NHibernateProfiler檢測如下:
看不到參數化的sql,能看到執行的sql,但看不出串連資料庫的次數。於是我改為串連sql server,用sql server profiler檢測了下串連的sql,由於mssql沒有序列的說法,因此只能看共用同一個session生命週期時,所有操作資料庫的sql,資料庫這邊檢測到的sql查詢次數,
設定檔如下:
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class ="native"></generator>
</id>
其他都一樣,
c#代碼如下:
var a = domainService.GetTestById3(1);
var a2 = domainService.GetTestById3(1);
var b = domainService.GetTestById3(2);
object o2 = domainService.AddTest(new DomainModel.Entities.Test() { name = "ab" });
用NHibernateProfiler檢測如下:
用sql server profiler檢測如下:
能明顯看到有3次資料庫的開啟關閉操作,因此我判斷雖然nhibernate共用一個session,部分操作感覺像是一個整體的執行,而且只是查詢操作時,NHibernateProfiler會把所有查詢操作的sql完了或者有插入資料庫操作時,才在介面上顯示查詢的幾次sql記錄,但NHibernateProfiler實際上還是對介面short sql中的每行記錄都有一次串連和關閉資料庫的查詢操作,配置用序列建立主鍵ID時,從NHibernateProfiler顯示也是兩次資料庫的查詢操作。
對NHibernate還不夠熟,李永京的nhibernate系列文章還不錯,要多學習學習,NH3又多了些特徵和功能,但我對NHibernate的二級緩衝擴充還比較感興趣,因為這個直接影響到終端使用者,希望以後可以多熟悉這塊。