剛學NHibernate的時候覺得,HQL挺好用的,但是終歸沒有與其他技術相關聯,只有NHibernate用到,一來容易忘記,二來沒有智能提示,排除錯誤什么的都不給力,直到看到一個同事用Linq to NHibernate,那代碼是相當的清晰明了,其實什么條件查詢,HQL什么的感覺只是一個NHibernate用到,很容易忘記。而SQL跟Linq是經常用的東西,還是SQL和Linq比較划算。今天就來寫下Linq to NHibernate。
引用NHibernate.Linq后,創建查詢時應該這樣
session.Query<Person_Model>()...
而不是
session.QueryOver<Person_Model>().AndNot(m => m.State).List();
以下運算符據說是在NHibernate.Linq命名空間里的,但是本人下載的默認NHibernate找不到,先列出所有的操作符,供以后可以查找
一、限制運算符
Where:篩選序列中的項目
WhereNot:反篩選序列中的項目
二、投影運算符
Select:創建部分序列的投影
SelectMany:創建部分序列的一對多投影
三、分區運算符(分頁常用到)
Skip:返回跳過指定數目項目的序列
SkipWhile:返回跳過不滿足表達式項目的序列
Take:返回具有指定數目項目的序列
TakeWhile:返回具有滿足表達式項目的序列
四、排序運算符
OrderBy:以升序按值排列序列
OrderByDescending:以降序按值排列序列
ThenBy:升序排列已排序的序列
ThenByDescending:降序排列已排序的序列
Reverse:顛倒序列中項目的順序(用於操作集合)
五、分組運算符
GroupBy:按指定分組方法對序列中的項目進行分組
六、設置運算符
Distinct:返回無重復項目的序列
Except:返回代表兩個序列差集的序列(用於操作集合)
Intersect:返回代表兩個序列交集的序列(用於操作集合)
Union:返回代表兩個序列交集的序列(用於操作集合)
七、轉換運算符
Cast:將序列中的元素轉換成指定類型
OfType:篩選序列中指定類型的元素
ToArray:從序列返回一個數組
ToDictionary:從序列返回一個字典
ToList:從序列返回一個列表
ToLookup:從序列返回一個查詢
ToSequence:返回一個IEnumerable序列
八、元素運算符
DefaultIfEmpty:為空序列創建默認元素(用於操作集合)
ElementAt:返回序列中指定索引的元素(用於操作集合)
ElementAtOrDefault:返回序列中指定索引的元素,或者如果索引超出范圍,則返回默認值(用於操作集合)
First:返回序列中的第一個元素
FirstOrDefault:返回序列中的第一個元素,或者如果未找到元素,則返回默認值
Last:返回序列中的最后一個元素(用於操作集合)
LastOrDefault:返回序列中的最后一個元素,或者如果未找到元素,則返回默認值(用於操作集合)
Single:返回序列中的單個元素
SingleOrDefault:返回序列中的單個元素,或者如果未找到元素,則返回默認值
九、生成運算符
Empty:生成一個空序列
Range:生成一個指定范圍的序列
Repeat:通過將某個項目重復指定次數來生成一個序列
十、限定符
All:確定序列中的所有項目是否滿足某個條件
Any:確定序列中是否有任何項目滿足條件
Contains:確定序列是否包含指定項目
十一、聚合運算符
Aggregate:對序列執行一個自定義方法
Average:計算數值序列的平均值
Count:返回序列中的項目數(整數)
LongCount:返回序列中的項目數(長型)
Min:查找數字序列中的最小數
Max:查找數字序列中的最大數
Sum:匯總序列中的數字
十二、連接運算符
Concat:將兩個序列連成一個序列
十三、聯接運算符
GroupJoin:通過歸組將兩個序列聯接在一起
Join:將兩個序列從內部聯接起來
我新建了一個張表,並添加了十幾條數據。
在NHibernate中,linq查詢通過session.QueryOver<T>()創建。我們先來看看NHibernate本身自帶的Linq提供的操作符。
注意下面生成的SQL語句是不同的(2016-11-14更新)
Where(m => m.Id > 0 && m.Name='xx' && m.Age > 0) 與 Where(m => m.Id > 0).And(m => m.Name='xx').And(m => m.Age > 0)
前者:
WHERE( ( this_.id= ? AND this_.name= ? ) AND this_.age= ? )
后者:
WHERE this_.id > 0 AND this_.Name= '' AND this_Age > 0
推薦使用后面的寫法。
1、And
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().And(m => m.State).List(); //查詢所有state字段為True的記錄 NHibernateHelper.CloseSession(); return list; }
以上生成的SQL語句為
exec sp_executesql N'SELECT this_.Id as Id1_0_, this_.name as name1_0_, this_.age as age1_0_, this_.state as state1_0_ FROM Person this_ WHERE this_.state = @p0',N'@p0 bit',@p0=1
可以看到And實際上相當於一條Where語句了。條件為True的返回。
我們把And換成Where再來看看生成的SQL語句。
exec sp_executesql N'SELECT this_.Id as Id1_0_, this_.name as name1_0_, this_.age as age1_0_, this_.state as state1_0_ FROM Person this_ WHERE this_.state = @p0',N'@p0 bit',@p0=1
呵呵,沒有區別。留待
//投影 IList<dynamic[]> ListKeyword = NHH.GetSession().QueryOver<Article>() .SelectList(list => list .Select(p => p.Id) .Select(p => p.Title) .Select(p => p.Keyword) ) .Where(m => m.BrowseMode) .Skip(SkipCount) .Take(rows) .List<dynamic[]>(); IList<dynamic> ListTS = new List<dynamic>(); foreach (dynamic[] d in ListKeyword) { ListTS.Add(new { Id = d[0], Title = d[1], Keyword = d[2] }); }
投影的一段C#代碼,專為IList<dynamic>之后,又可以當普通對象一樣使用,並且這樣不用創建新類
2、AndNot
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().AndNot(m => m.State).List(); //查詢所有state字段等於false的記錄 NHibernateHelper.CloseSession(); return list; }
我們來看看生成的SQL語句
exec sp_executesql N'SELECT this_.Id as Id1_0_, this_.name as name1_0_, this_.age as age1_0_, this_.state as state1_0_ FROM Person this_ WHERE not (this_.state = @p0)',N'@p0 bit',@p0=1
留意到它只比And操作符的區別在於在where條件后加了個not()
3、AndRestrictionOn
AndRestrictionOn的中文意思是,添加限制條件。
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().AndRestrictionOn(m => m.Name).IsLike("諸",NHibernate.Criterion.MatchMode.Anywhere).List(); NHibernateHelper.CloseSession(); return list; }
第二個參數IsLike的第二個參數NHibernate.Criterion.MatchMode.Anywhere是一個枚舉,指示百分號應該添加到哪里?
生成的SQL語句如下:
exec sp_executesql N'SELECT this_.Id as Id1_0_, this_.name as name1_0_, this_.age as age1_0_, this_.state as state1_0_ FROM Person this_ WHERE this_.name like @p0',N'@p0 nvarchar(4000)',@p0=N'%諸%'
很多重要的查詢都在AndRestrictionOn這個方法里,比如"in","Between"符號等等,覺得SQL不好寫的時候,就可以查查這個。
4、JoinAlias
JoinAlias主要用於連接表並添加別名,對應的SQL字句是Join,根據Person查Country
public IList<Person_Model> Select() { Country_Model country = null; //必須定義一個用於別名的Country_Model,且必須為null IList<Person_Model> list = session.QueryOver<Person_Model>().JoinAlias(m => m.Country, () => country).List(); NHibernateHelper.CloseSession(); return list; }
生成的sql語句為
SELECT this_.Id as Id0_1_, this_.name as name0_1_, this_.age as age0_1_, this_.state as state0_1_, this_.CountryId as CountryId0_1_, country1_.CountryId as CountryId1_0_, country1_.CountryName as CountryN2_1_0_ FROM Person this_ inner join Country country1_ on this_.CountryId=country1_.CountryId
該查詢會把Country的信息也查出來。
其次,JoinAlias還可以支持第三個參數,其用於指定外連接的類型。
例如將JoinAlias改為:
public IList<Person_Model> Select() { Country_Model country = null; //必須定義一個用於別名的Country_Model,且必須為null IList<Person_Model> list = session.QueryOver<Person_Model>().JoinAlias(m => m.Country, () => country,NHibernate.SqlCommand.JoinType.LeftOuterJoin).List(); NHibernateHelper.CloseSession(); return list; }
則,生成的SQL語句為:
SELECT this_.Id as Id0_1_, this_.name as name0_1_, this_.age as age0_1_, this_.state as state0_1_, this_.CountryId as CountryId0_1_, country1_.CountryId as CountryId1_0_, country1_.CountryName as CountryN2_1_0_ FROM Person this_ left outer join Country country1_ on this_.CountryId=country1_.CountryId
NHibernate.SqlCommand.JoinType是一個枚舉類型,其支持的值有
枚舉值 對應的SQL
FullJoin full outer join
InnerJoin inner join
LeftOuterJoin left outer join
RightOuterJoin right outer join
None 不連接,不連接還要這個參數干嘛?
5、JoinQueryOver
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().OrderBy(p => p.Age).Desc.Inner.JoinQueryOver<Country_Model>(o => o.Country).List(); NHibernateHelper.CloseSession(); return list; }
生成的SQL語句為
SELECT this_.Id as Id0_1_, this_.name as name0_1_, this_.age as age0_1_, this_.state as state0_1_, this_.CountryId as CountryId0_1_, country_mo1_.CountryId as CountryId1_0_, country_mo1_.CountryName as CountryN2_1_0_ FROM Person this_ inner join Country country_mo1_ on this_.CountryId=country_mo1_.CountryId ORDER BY this_.age desc
JoinQueryOver與JoinAlias只有返回不同,返回不同就可以繼續銜接。比如:
NHH.GetSession().QueryOver<Permission>().JoinQueryOver<Role>(m => m.Roles, () => role).JoinQueryOver<User>(m => m.Users, () => user).Where(m => m.Account == Account).List<Permission>();
在多表Join的情況下,你條查詢條件從Permission => Roles => User。如果用JoinAlias就一直是對表Permission操作,沒有辦法轉到User。
也就是說,本來Where()條件時,使用的參數是第一個表里面的,如果想用關聯表來進行Where篩選,就需要使用JoinQueryOver。2016-11-19
6、OrderBy
Order主要用於排序,相當於SQL語句里面的order by。
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().OrderBy(p => p.Age).Desc.List(); //按照年齡降序排序 NHibernateHelper.CloseSession(); return list; }
生成的SQL語句為
SELECT this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_ FROM Person this_ ORDER BY this_.age desc
其中OrderBy方法后面能跟的屬性有兩個,分別是Asc與Desc與數據庫的SQL語句對應相同意思。
7、OrderByAlias
8、Lock
9、Select
告知NHibernate你想要查詢的是什么東西。
IList<int> list1 = session.QueryOver<Person_Model>().Select(p => p.Age).List<int>(); //獲取所有年齡的IList集合 NHibernateHelper.CloseSession(); return list;
生成的SQL語句為
SELECT this_.age as y0_ FROM Person this_
實際上與之對應的還有一個SelectList,它的作用更加強大,必須說了,放一條示例上來:
var ListArticleProduct = NHH.GetSession().QueryOver<Article>() .OrderBy(m => m.Id).Desc .SelectList(list => list .SelectGroup(p => p.Id) .Select(p => p.PathAlias) .Select(p => p.Title) .Select(p => p.ThumbnailPath) ) .JoinQueryOver(m => m.Tags, () => ArtTag, NHibernate.SqlCommand.JoinType.LeftOuterJoin) .Where(m => m.Type == 2).AndRestrictionOn(m => m.Name) .IsLike(Model.Tags[0].Name, NHibernate.Criterion.MatchMode.Anywhere) .Take(3) .List<dynamic[]>();
它生成的SQL語句如下:
SELECT this_.id as y0_, this_.path_alias as y1_, this_.title as y2_, this_.thumbnail_path as y3_
FROM article this_
left outer join tag_article_relation tags3_ on this_.id=tags3_.art_id
left outer join article_tag arttag1_
on tags3_.tag_id=arttag1_.id
WHERE arttag1_.type = ? and arttag1_.name like ?
GROUP BY this_.id
ORDER BY this_.id desc
LIMIT ?
無它,加了一個Group By在Order By前面用於去除重復數據,並且返回投影只有4個列,並在結果放在一個動態類型數組里,不用新定義類,就能夠獲取任意想要的字段形成的IList<dinamic[]>,包括Group By Sum Count等形成的隊列。 2016-12-31更新
關於投影推薦一個不錯的地址:http://www.andrewwhitaker.com/blog/2014/03/22/queryover-series-part-3-selecting-and-transforming/
以及http://www.cnblogs.com/dddd218/archive/2011/05/16/2047857.html
今晚查找一個問題居然發現這篇文章被別人復制得到處都是,也沒留出處,沒事,我也經常喜歡復制別人的不留出處。
10、ThenBy
與SQL語句中的then by同義。
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().OrderBy(p => p.Age).Asc.ThenBy(p => p.Id).Desc.List(); NHibernateHelper.CloseSession(); return list; }
生成的SQL語句為
SELECT this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_ FROM Person this_ ORDER BY this_.age asc, this_.Id desc
11、Where
添加where條件,與SQL語句同義。
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().Where(p => p.Age > 50).List(); NHibernateHelper.CloseSession(); return list; }
生成的SQL語句為
exec sp_executesql N'SELECT this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_ FROM Person this_ WHERE this_.age > @p0',N'@p0 int',@p0=50
12、WhereNot
添加where條件,只是前面加了個Not。
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().WhereNot(p => p.Age > 50).List(); NHibernateHelper.CloseSession(); return list; }
生成的SQL語句為
exec sp_executesql N'SELECT this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_ FROM Person this_ WHERE not (this_.age > @p0)',N'@p0 int',@p0=50
13、Skip
跳過指定數量的記錄
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().Skip(5).List(); NHibernateHelper.CloseSession(); return list; }
生成的SQL語句為
exec sp_executesql N'SELECT TOP (2147483647) Id0_0_, name0_0_, age0_0_, state0_0_, CountryId0_0_ FROM (SELECT this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_, ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row FROM Person this_) as query WHERE query.__hibernate_sort_row > @p0 ORDER BY query.__hibernate_sort_row',N'@p0 int',@p0=5
14、Take
獲取指定數量的記錄,與Skip配合使用是經常用到的分頁效果。
public IList<Person_Model> Select() { IList<Person_Model> list = session.QueryOver<Person_Model>().Take(5).List(); NHibernateHelper.CloseSession(); return list; }
生成的SQL語句為
exec sp_executesql N'SELECT TOP (@p0) this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_ FROM Person this_',N'@p0 int',@p0=5
15、RowCount()
統計符合條件的記錄,相當於Select Count(*) from...
int count = session.QueryOver<Person_Model>().RowCount(); NHibernateHelper.CloseSession();
生成的SQL語句為
SELECT count(*) as y0_ FROM Person this_
16、RowCountInt64
也是統計記錄,與RowCount沒什么區別,只是返回的記錄是long類型的。
long count = session.QueryOver<Person_Model>().RowCountInt64(); NHibernateHelper.CloseSession();
生成的SQL語句為
SELECT count(*) as y0_ FROM Person this_
17、SingleOrDefault
返回符合條件的第一條記錄,當為空是,返回一個各屬性為null的對應類型的對象。
Person_Model p = session.QueryOver<Person_Model>().Where(m => m.Age == 10).SingleOrDefault(); NHibernateHelper.CloseSession();
生成的SQL語句為
exec sp_executesql N'SELECT this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_ FROM Person this_ WHERE this_.age = @p0',N'@p0 int',@p0=10
18、Future
Future()與List()的區別在於Future返回的是IEnumerable<>集合,而List()返回的是IList()。
IEnumerable<Person_Model> list1 = session.QueryOver<Person_Model>().Where(m => m.Age > 10).Future(); NHibernateHelper.CloseSession();
與SQL語句無關
19、List
List()將結果集合封裝為IList()接口集合返回。
IList<Person_Model> list = session.QueryOver<Person_Model>().WhereRestrictionOn(p => p.Age).IsIn(ints).List();
NHibernateHelper.CloseSession();
與SQL語句無關。
20、FutureValue()
IFutureValue<Person_Model> list1 = session.QueryOver<Person_Model>().WhereRestrictionOn(p => p.Age).IsIn(ints).FutureValue();
Person_Model p1 = list1.Value;
FutureValue()這是一個非常簡單的接口,里面就一個泛型的Value屬性,也就是說.FutureValue()這個東西只是裝載了一個對應查詢類型的對象而已。
與SQL語句無關。
21、WhereRestrictionOn
這個東西與前面說的AdnRestrictionOn是一樣的,也是可以添加條件啥亂七八糟的。
IEnumerable<Person_Model> list1 = session.QueryOver<Person_Model>().WhereRestrictionOn(p => p.Age).IsIn(ints).Future();
NHibernateHelper.CloseSession();
生成的SQL代碼為:
exec sp_executesql N'SELECT this_.Id as Id0_0_, this_.name as name0_0_, this_.age as age0_0_, this_.state as state0_0_, this_.CountryId as CountryId0_0_ FROM Person this_ WHERE this_.age in (@p0, @p1, @p2)',N'@p0 int,@p1 int,@p2 int',@p0=20,@p1=25,@p2=31