NHibernate Linq查詢 擴充套件增強 (第九篇)
在上一篇的Linq to NHibernate的介紹當中,全部是namespace NHibernate名稱空間中的IQueryOver<TRoot, TSubType>介面提供的。IQueryOver<TRoot, TSubType>這個藉口實際上會被翻譯成條件查詢(Criteria Queries)。
實際上Linq to NHibernate更加強大。我們先引入名稱空間NHibernate.Linq,這裡面有Linq to NHibernate更強大的擴充套件。
一、Fetch立即載入(避免延遲載入)
我們先來看看,NHibernate的延遲載入可能存在的問題:
延遲載入產生的SQL執行方式:
static void Main(string[] args) { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); using (ISession session = sessionFactory.OpenSession()) { IList<PersonModel> ListPerson = session.QueryOver<PersonModel>().List(); foreach (PersonModel p in ListPerson) { Console.WriteLine(p.PersonId + p.PersonName + p.Country.CountryName); } } Console.ReadKey(); }
執行結果為:
這延遲載入玩大發了吧。foreach()一次,讀一條記錄,這... 看到上面語句的FROM Country了嗎,其實主要是讀Person的時候沒有把Country也讀出來,弄得每次foreach()的時候必須在到資料庫讀取Person對應的Country造成的,如果我們不想因為跨表查詢到Country就要在載入的時候,把Person所對應的Country也載入過來。
立即載入,還好,有Fetch方法,我們來看看如下程式碼:
static void Main(string[] args) { ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory(); using (ISession session = sessionFactory.OpenSession()) { IList<PersonModel> ListPerson = session.Query<PersonModel>().Fetch(p => p.Country).ToList(); foreach (PersonModel p in ListPerson) { Console.WriteLine(p.PersonId + p.PersonName + p.Country.CountryName); } } Console.ReadKey(); }
執行的SQL語句為:
這個還像話,就應該這樣嗎。NHibernate預設開啟延遲載入特性,以便其他查詢順利應用延遲載入帶來的益處。而當我們不希望延遲載入的時候,可以通過Fetch()程式設計的方式控制。不錯。以上程式,Fetch的作用是載入Person時,強制載入與Person關聯的Country。
下面再來說說立即載入一些其他的東西,我們將原來的資料庫改成如下:
1、多個關聯
Person除了有一個所屬國家外,還有一個所屬學校。那麼我們要輸出一個Person的CountryName與SchoolName。又應該怎麼處理呢?
static void Main(string[] args) { ISessionFactory SessionFactory = (new Configuration()).Configure().BuildSessionFactory(); using (ISession session = SessionFactory.OpenSession()) { IList<PersonModel> ListPerson = session.Query<PersonModel>().Fetch(p => p.Country).Fetch(p => p.School).ToList(); foreach (PersonModel p in ListPerson) { Console.WriteLine(p.Name + ":" + p.Country.CountryName + ":" + p.School.SchoolName); } } Console.ReadKey(); }
我們得Fetch().Fetch()把資料一次性載入過來,否則還是會出現foreach()一次,查詢一次School的情況。
以上程式碼輸出如下:
2、巢狀關聯
在上一節的圖中,Person屬於Country,而Country又屬於一個Area。如果我們Fetch()了Country,那麼如果要輸出AreaName還是要再次查資料庫。因此,我們希望在讀取Perosn時,順帶讀出關聯的Country,再順帶讀出關聯的Area怎麼做到呢?
static void Main(string[] args) { ISessionFactory SessionFactory = (new Configuration()).Configure().BuildSessionFactory(); using (ISession session = SessionFactory.OpenSession()) { IList<PersonModel> ListPerson = session.Query<PersonModel>().Fetch(p => p.Country).ThenFetch(c => c.Area).ToList(); foreach (PersonModel p in ListPerson) { Console.WriteLine(p.Name + ":" + p.Country.CountryName + ":" + p.Country.Area.AreaName); } } Console.ReadKey(); }
輸出結果如下:
以上程式碼一次過讀出所需的資料,毫不做作。
Fetch與FetchMany的區別
Fetch與FetchMany的區別與Select與SelectMany的區別一樣。看了一下,方法簽名,主要是有一個引數的區別。
public static INhFetchRequest<TOriginating, TRelated> Fetch<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, TRelated>> relatedObjectSelector); public static INhFetchRequest<TOriginating, TRelated> FetchMany<TOriginating, TRelated>(this IQueryable<TOriginating> query, Expression<Func<TOriginating, IEnumerable<TRelated>>> relatedObjectSelector);
留意到方法簽名只是查了一點點,但是對於根據Area獲取Country再獲取Person來說,就非FetchMany不可了。因為Fetch()的引數不允許為集合。
例如,我們查出所有的地區,然後列出地區的所有國家,再列出所有的PersonName:
//-------------------------------------------------------------------------------------------------此處c是IEnumerable<ContryModel> IList<AreaModel> ListArea = NSession.Query<AreaModel>().FetchMany(a => a.ListCountry).ThenFetchMany(c => c.ListPerson).ToList(); //IList<AreaModel> ListArea = NSession.Query<AreaModel>().Fetch(a => a.ListCountry).ThenFetch(c => c.ListPerson).ToList(); 這麼寫編譯器就報錯 foreach (AreaModel area in ListArea) { Console.WriteLine(area.AreaName); foreach (CountryModel c in area.ListCountry) { Console.WriteLine(c.CountryName); foreach (PersonModel p in c.ListPerson) { Console.WriteLine(p.Name); } } }
輸出如下:
區別在於FetchMany,ThenFetchMany接受IEnumerable<T>型別的資料輸入,而Fetch,FetchMany不支援。
二、Linq使用Cache
Linq-Cache說明:
-
Cacheable 為一個查詢顯示啟用二級快取;
-
CacheMode 快取模式, 有如下可選:
- Ignore:更新資料時將二級快取失效,其它時間不和二級快取互動
- Put:向二級快取寫資料,但不從二級快取讀資料
- Get:從二級快取讀資料,僅在資料更新時向二級快取寫資料
- Normal:預設方式。從二級快取讀/寫資料
- Refresh:向二級快取寫資料,想不從二級快取讀資料,通過在配置檔案設定 cache.use_minimal_puts從資料庫中讀取資料時,強制二級快取重新整理
-
CacheRegion 給查詢快取指定了特定的命名快取區域, 如果兩個查詢相同, 但是指定的 CacheRegion 不同, 則也會從資料庫查詢資料。
-
1、在使用快取之前,先來開啟NHibernate二級快取。
<!-- 配置二級快取實現程式 --> <property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider</property> <!-- 開啟二級快取 --> <property name="cache.use_second_level_cache">true</property> <!-- 在查詢中開啟二級快取 --> <property name="cache.use_query_cache">true</property> <!-- 配置對映的二級快取 --> <class-cache class="Model.PersonModel,Model" usage="read-write"/>
2、在要使用快取的實體類的對映檔案上,Id節點前加上這一行:
<!-- 配置快取策略 --> <cache usage="read-write"/>
然後,還是利用上面的例子來測試。
static void Main(string[] args) { ISessionFactory _sessionFactory = new Configuration().Configure().BuildSessionFactory(); using(ISession NSession = _sessionFactory.OpenSession()) { IList<PersonModel> ListPerson = NSession.Query<PersonModel>().Cacheable().CacheMode(CacheMode.Normal).CacheRegion("AllCategories").ToList(); foreach (PersonModel p in ListPerson) { Console.WriteLine(p.Name); } } Console.WriteLine("========================================================="); using (ISession NSession = _sessionFactory.OpenSession()) { IList<PersonModel> ListPerson2 = NSession.Query<PersonModel>().Cacheable().CacheMode(CacheMode.Normal).CacheRegion("AllCategories").ToList(); foreach (PersonModel p in ListPerson2) { Console.WriteLine(p.Name); } } Console.ReadKey(); }
輸出結果如下:
這個沒什麼好說的了,看懂那3個方法的說明好了。
相關推薦
NHibernate Linq查詢 擴充套件增強 (第九篇)
在上一篇的Linq to NHibernate的介紹當中,全部是namespace NHibernate名稱空間中的IQueryOver<TRoot, TSubType>介面提供的。IQueryOver<TRoot, TSubType>這個藉口實際
MySQL數據庫學習【第九篇】索引原理與慢查詢優化
xxx 結構 復合 unix select查詢 全文搜索 等等 學習 獲取數據 一、介紹 1.什麽是索引? 一般的應用系統,讀寫比例在10:1左右,而且插入操作和一般的更新操作很少出現性能問題,在生產環境中,我們遇到最多的,也是最容易出問題的,還是一些復雜的查詢操作,因此對
實踐課-------(第九篇)
視圖 clas 環境配置 項目 開源 nfa nco ext contex 通過這十天的框架搭建學習,學會了環境配置,及其測試,得出以下總結 1.創建WEB工程添加struts支持 2.分包 3添加spring支持 4.添加spring配置文件 5.在web.x
第九篇:網絡編程補充與進程
ans 秘鑰 可能 con com eas inpu 域名系統) import 本篇內容 udp協議套接字 開啟進程的方式 多進程實現並發的套接字通信 join方法 守護進程 同步鎖 進程隊列 生產者消費者模型 進程池 paramiko模塊 一、 udp協議套接字
第九篇 float浮動
默認 spa 寬度 空格 位移 hidden 選擇器 rod otto float浮動 首先老師要聲明,浮動這一塊,和邊距、定位相比,它是比較難的,但是用它,頁面排版會更好。 這節課就直接上代碼,看著代碼去學浮動。 我們先弄一個div,給它一個背景顏色: HTML:
第九篇:Spark SQL 源碼分析之 In-Memory Columnar Storage源碼分析之 cache table
gravity base field eof 授權 葉子節點 command ref gist /** Spark SQL源碼分析系列文章*/ Spark SQL 可以將數據緩存到內存中,我們可以見到的通過調用cache table tableName即可將一張表緩
數據結構第九篇——棧與遞歸
分解 是什麽 運行時 使用 執行過程 非遞歸算法 long 應該 char 棧還有一個重要應用是在程序設計中實現遞歸。遞歸是計算機 科學和數學中一種解決問題的及其重要的方法。在數據結構中,可以用它來設計簡單。易於理解的算法,特別是在一些具有遞歸定義的結構上設計算法。 遞歸的
mysql第九篇文章~一個mysql案例的排查
文章 pla 既然 排查 問題 一點 一個 相關 聯系 背景:測試環境下發現大量select查詢,而且負載飆升到90+ 排查思路: 1 老規則,按照排錯腳本走一圈,規劃出幾個元素(1 針對庫訪問的統計 2針對具體語句類型的統計),發現有大量的se
第九篇 數據表設計和保存item到json文件
初始 self pycha cti ensure comment 項目 div init 上節說到Pipeline會攔截item,根據設置的優先級,item會依次經過這些Pipeline,所以可以通過Pipeline來保存文件到json、數據庫等等。 下面是自定義json
【Linux筆記】第九篇、添加MariaDB用戶、設置權限
.com 生效 mysq local 分享圖片 style info user 創建 一、登錄mysql 二、創建用戶 create user [email protected] identified by ‘dev‘; 三、給新建用戶授權數據庫h_user的權限 授權
秒殺多線程第九篇 經典線程同步總結 關鍵段 事件 互斥量 信號量
事件觸發 內核 clas article ase 理解 handle order 線程並發 本文轉載於:http://blog.csdn.net/morewindows/article/details/7538247 來詳細介紹常用的線程同步互斥機制——關鍵段、事件、互斥量
第九篇測試
展開 恢復 win row ogr 排序 ges 所有 字符 sublime使用技巧 1:安裝漂亮的編程字體http://pan.baidu.com/s/1xMex9 下載"程序編寫字體 – Yahei Consolas Hybrid",雙擊安裝 2:解壓sublime到你
python全棧開發【第九篇】Python常用模塊一(主要是re正則和collections)
順序 常用模塊 內置 object 簡潔 整體 re.search lec 快速 一、認識模塊 什麽是模塊:一個模塊就是一個包含了python定義和聲明的文件,文件名就是加上.py的後綴,但其實import加載的模塊分為四個通用類別 : 1.使用python
web前端【第九篇】JS的DOM對象三
內部 eat direct 詞法 表達 遍歷 -h bmi 常見 一、JS中for循環遍歷測試 for循環遍歷有兩種 第一種:是有條件的那種,例如 for(var i = 0;i<ele.length;i++){} 第二種:for (var i in li )
Django 【第九篇】自定義的分頁器組件
ota pen mod href render art 頁碼 .get led 一、分頁的實現與使用 class Pagination(object): """ 自定義分頁 """ def __init__(self,current_pa
Flask 【第九篇】flask-script組件
-c 運行方式 doc latest odin __name__ 參數 修飾 bar Flask Script擴展提供向Flask插入外部腳本的功能,包括運行一個開發用的服務器,一個定制的Python shell,設置數據庫的腳本,cronjobs,及其他運行在web應用
Python進階【第九篇】裝飾器
turn spa none app light fun rap log python 什麽是裝飾器 裝飾器本身就是函數,並且為其他函數添加附加功能 裝飾器的原則:1.不修改被裝飾對象的源代碼 2.不修改被裝飾對象的調用方式裝飾器=高階函數+函數嵌套+閉包 # res=t
第九篇 AJAX
以及 索引 檢索 list != ret env ddl 常見 AJAX 閱讀目錄(Content) 概述 AJAX常見應用情景 AJAX的優缺點 jQuery實現的AJAX $.ajax參數 AJAX請求如何設置csrf_token 序列化
python學習【第九篇】python面向對象編程
同名方法 ron 重寫 結構 程序 如果 覆蓋 -a base 一、面向對象了解 面向對象編程——Object Oriented Programming,簡稱OOP,是一種程序設計思想。OOP把對象作為程序的基本單元,一個對象包含了數據和操作數據的函數。 Pytho
Flask最強攻略 - 跟DragonFire學Flask - 第九篇 Flask 中的藍圖(BluePrint)
border value body -418 添加 onf 訪問 們的 導入 藍圖,聽起來就是一個很宏偉的東西 在Flask中的藍圖 blueprint 也是非常宏偉的 它的作用就是將 功能 與 主服務 分開怎麽理解呢? 比如說,你有一個客戶管理系統,最開始的時候,只有一個