NHibernate-通過SQL-Query返回DataSet之一


      最近一直在使用NHibernate做開發,發現雖然NHibernate實體查詢很強大,但是還是沒有SQL查詢方便,而且有時候我得需要返回多張表的數據,而且必須有字段名,這樣必須得返回一個DataSet或DataTable類型的對象。我不可能為了這一個簡單的多表查詢就去整一個實體來映射,這樣也太麻煩了。我也不想就因為這樣一個經常碰到的小問題就去寫個存儲過程,這樣也鬧大了點。因此我想能不能直接通過配置Sql-Query查詢來得到一個DataSet呢?

      一、准備測試環境

      1、創建一解決方案,添加三項目,一個類似於實體library,一個是測試項目,另一個是NHibernate的源碼項目。

     

 

     TestLb中主要是一個實體DriverInfo.cs及其映射文件。MyTest項目中主要是UnitTest1.cs文件以及其它一些應用類和配置文件。TestLb和MyTest項目中包含一個對NHibernate源碼項目的引用,因文件太多,不提供下載,可到NHibernate官網下載:

https://github.com/nhibernate/nhibernate-core/tree/master/src

    下面是上面TestLb和MyTest兩項目下載地址,僅供參考:

http://files.cnblogs.com/wuwei_chen/src.zip

    我的數據庫環境是Oracle,所以請根據自己的情況配置實體映射文件以及測試項目中hibernate.cfg.xml文件。解決方案中添加好三項目后,注意給實體項目和測試項目添加NHibernate的 Reference。

2、簡單了解下sql-query查詢

     DriverInfo.hbm.xml映射文件下如下代碼:

  <sql-query name="GetDataSetTest">
   <!--<return class="System.Data.DataSet,System.Data">
    </return>-->
    <!--<return class="DataSet">
    </return>-->
    select  * from Fleet_DriverInfo where rownum&lt;2
  </sql-query>

            MyTest項目中UnitTest1下測試方法:

    [TestMethod]
        public void TestReaderWay()
        {
              ISessionFactory factory=SessionFactory.SessionFac;
              ISession session = factory.OpenSession();
            IQuery query = session.GetNamedQuery("GetDataSetTest");
             
           var res0 = query.List();
              //var res = query.QueryDataSet();
        }

       至於上述代碼中SessionFactory只是一個實現了單鍵模式的用於返回一個ISessionFactory類型的簡單類。一個簡單的sql-query查詢測試就這樣了。

       3、開始摸索

       運行上述測試代碼,返回來的對象是一個IEnurable的object[]數組,顯然不是我們需要的。我們查看IQuery接口代碼,發現其有一個返回泛型list的方法,那能否用泛型返回DataSet呢?

      修改上面測試方法中一句代碼:    

 var res0 = query.List<DataSet>()

 執行報如下錯誤 :

     System.Object[]" is not of type "System.Data.DataSet" and cannot be used in this generic collection

那如果將映射文件中的Sql-query中的配置改成如下呢:

 <sql-query name="GetDataSetTest">
   <return class="System.Data.DataSet,System.Data">
    </return>
    <!-- or <return class="DataSet">
    </return>-->
    select  * from Fleet_DriverInfo where rownum&lt;2
  </sql-query>

如果改成上面兩種設置返回類型,更加不行了,在BuildSessionFactory階段就會報錯。
  No persister for :System.Data.DataSet......

   看來是無法這樣返回DataSet了,那只好考慮是否能基於NHibernate的源碼做擴展了。

    二、了解NHibernate的sql-query查詢機制

          既然是了解NHibernate的查詢機制,肯定得調試NHibernate的源碼了。為了節約大家按F5、F9、F11、F12的次數,我直接先列出一些重要的斷點位置。

          SqlQueryImpl.cs   NHibernate=>Impl=>SqlQueryImpl.cs
          斷點位置:127 line 

public override IList List()
{
   ......
      return Session.List(spec, qp);
   ......
}

 

 SessionImpl.cs NHibernate=>Impl=>SessionImpl.cs
斷點位置:2163  line

public override void ListCustomQuery(ICustomQuery customQuery, QueryParameters queryParameters, IList results)
		{
		    ......					
ArrayHelper.AddAll(results, loader.List(this, queryParameters)); ...... }

 

 

由於需要設置斷點的位置太多,下面我就不一一貼出設置斷點的全部方法了,只貼出設置斷點的代碼。

CustomLoader.cs NHibernate=>Loader=>Custom=>CustomLoader.cs
斷點位置:276 line

public IList List(ISessionImplementor session, QueryParameters queryParameters)
		{
			return List(session, queryParameters, querySpaces, resultTypes);
		}

 

 Loader.cs NHibernate=>Loader=>Loader.cs
斷點位置:1495 line

斷點位置:1532 line

斷點位置:1624 line

斷點位置:249 line

斷點位置:417 line

 protected IList List(ISessionImplementor session, QueryParameters queryParameters, ISet<string> querySpaces, IType[] resultTypes)
        {
           ......
                return ListUsingQueryCache(session, queryParameters, querySpaces, resultTypes);
         ......
        }

 private IList ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters)
        {
            return GetResultList(DoList(session, queryParameters), queryParameters.ResultTransformer);
        }
protected IList DoList(ISessionImplementor session, QueryParameters queryParameters)
        {
           ......
                result = DoQueryAndInitializeNonLazyCollections(session, queryParameters, true);
          ......
        }

 private IList DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies)
        {
         ......
                    result = DoQuery(session, queryParameters, returnProxies);
        ......
        }
 private IList DoQuery(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies)
        {
            ......
            IDbCommand st = PrepareQueryCommand(queryParameters, false, session);

            IDataReader rs = GetResultSet(st, queryParameters.HasAutoDiscoverScalarTypes, queryParameters.Callable, selection,
                                          session);
......
}

    在此,一些重要的斷點位置設置好了,開始調試了。因為這篇隨筆太長了,所以只好另起一篇了。下一篇主要介紹如何擴展NHibernate的 sql-query來返回DataSet。

  有興趣的同仁可以先按照我上面介紹的設置好的一些斷點,跟蹤調試幾次,對理解NHibernate的框架有非常好的幫助。

 

 

        

         

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM