NHibernate 數據查詢之Linq to NHibernate

 剛學NHibernate的時候以爲,HQL挺好用的,可是終歸沒有與其餘技術相關聯,只有NHibernate用到,一來容易忘記,二來沒有智能提示,排除錯誤什麼的都不給力,直到看到一個同事用Linq to NHibernate,那代碼是至關的清晰明瞭,其實什麼條件查詢,HQL什麼的感受只是一個NHibernate用到,很容易忘記。而SQL跟Linq是常常用的東西,仍是SQL和Linq比較划算。今天就來寫下Linq to NHibernate。html

  引用NHibernate.Linq後,建立查詢時應該這樣sql

  session.Query<Person_Model>()...數據庫

  而不是數組

  session.QueryOver<Person_Model>().AndNot(m => m.State).List();session

  如下運算符聽說是在NHibernate.Linq命名空間裏的,可是本人下載的默認NHibernate找不到,先列出全部的操做符,供之後能夠查找this

  1、限制運算符spa

Where:篩選序列中的項目
WhereNot:反篩選序列中的項目hibernate

  2、投影運算符code

Select:建立部分序列的投影
SelectMany:建立部分序列的一對多投影orm

3、分區運算符(分頁經常使用到)

Skip:返回跳過指定數目項目的序列
SkipWhile:返回跳過不知足表達式項目的序列
Take:返回具備指定數目項目的序列
TakeWhile:返回具備知足表達式項目的序列

4、排序運算符

OrderBy:以升序按值排列序列
OrderByDescending:以降序按值排列序列
ThenBy:升序排列已排序的序列
ThenByDescending:降序排列已排序的序列
Reverse:顛倒序列中項目的順序(用於操做集合)

5、分組運算符

GroupBy:按指定分組方法對序列中的項目進行分組

6、設置運算符

Distinct:返回無重複項目的序列
Except:返回表明兩個序列差集的序列(用於操做集合)
Intersect:返回表明兩個序列交集的序列(用於操做集合)
Union:返回表明兩個序列交集的序列(用於操做集合)

7、轉換運算符

Cast:將序列中的元素轉換成指定類型
OfType:篩選序列中指定類型的元素
ToArray:從序列返回一個數組
ToDictionary:從序列返回一個字典
ToList:從序列返回一個列表
ToLookup:從序列返回一個查詢
ToSequence:返回一個IEnumerable序列

8、元素運算符

DefaultIfEmpty:爲空序列建立默認元素(用於操做集合)
ElementAt:返回序列中指定索引的元素(用於操做集合)
ElementAtOrDefault:返回序列中指定索引的元素,或者若是索引超出範圍,則返回默認值(用於操做集合)
First:返回序列中的第一個元素
FirstOrDefault:返回序列中的第一個元素,或者若是未找到元素,則返回默認值
Last:返回序列中的最後一個元素(用於操做集合)
LastOrDefault:返回序列中的最後一個元素,或者若是未找到元素,則返回默認值(用於操做集合)
Single:返回序列中的單個元素
SingleOrDefault:返回序列中的單個元素,或者若是未找到元素,則返回默認值

9、生成運算符

Empty:生成一個空序列
Range:生成一個指定範圍的序列
Repeat:經過將某個項目重複指定次數來生成一個序列

10、限定符

All:肯定序列中的全部項目是否知足某個條件
Any:肯定序列中是否有任何項目知足條件
Contains:肯定序列是否包含指定項目

11、聚合運算符

Aggregate:對序列執行一個自定義方法
Average:計算數值序列的平均值
Count:返回序列中的項目數(整數)
LongCount:返回序列中的項目數(長型)
Min:查找數字序列中的最小數
Max:查找數字序列中的最大數
Sum:彙總序列中的數字

12、鏈接運算符

Concat:將兩個序列連成一個序列

十3、聯接運算符

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

  推薦使用後面的寫法。

  一、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>以後,又能夠當普通對象同樣使用,而且這樣不用建立新類

  二、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()

  三、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很差寫的時候,就能夠查查這個。

  四、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              不鏈接,不鏈接還要這個參數幹嗎?

    五、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

    六、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語句對應相贊成思。

    七、OrderByAlias

    八、Lock

     九、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

  今晚查找一個問題竟然發現這篇文章被別人複製獲得處都是,也沒留出處,沒事,我也常常喜歡複製別人的不留出處。

    十、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

 

    十一、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

    十二、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

    1三、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

    1四、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

    1五、RowCount()

      統計符合條件的記錄,至關於Select Count(*) from...

            int count = session.QueryOver<Person_Model>().RowCount();
            NHibernateHelper.CloseSession(); 

      生成的SQL語句爲

    SELECT count(*) as y0_ FROM Person this_

    1六、RowCountInt64

      也是統計記錄,與RowCount沒什麼區別,只是返回的記錄是long類型的。

            long count = session.QueryOver<Person_Model>().RowCountInt64();
            NHibernateHelper.CloseSession();   

       生成的SQL語句爲

  SELECT count(*) as y0_ FROM Person this_

    1七、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

    1八、Future

      Future()與List()的區別在於Future返回的是IEnumerable<>集合,而List()返回的是IList()。

            IEnumerable<Person_Model> list1 = session.QueryOver<Person_Model>().Where(m => m.Age > 10).Future();
            NHibernateHelper.CloseSession();   

      與SQL語句無關

    1九、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語句無關。

    2一、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
相關文章
相關標籤/搜索