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