在上一篇的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。

  若是需要加分页什么的:

IList<ArticleBase> ListArticlePic = NHH.GetSession().QueryOver<ArticleBase>()
.Where(m => m.Knowledge && m.IsAudit).OrderBy(m => m.Id).Desc.Fetch(m => m.ArtContent).Eager.Skip(SkipCount).Take().List();

  1、Eager: 立即加载;

  2、Default:根据配置设定的方式加载;

  3、Lazy: 延时加载

  下面再来说说立即加载一些其他的东西,我们将原来的数据库改成如下:

  

  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 缓存模式, 有如下可选:

      1. Ignore:更新数据时将二级缓存失效,其它时间不和二级缓存交互
      2. Put:向二级缓存写数据,但不从二级缓存读数据
      3. Get:从二级缓存读数据,仅在数据更新时向二级缓存写数据
      4. Normal:默认方式。从二级缓存读/写数据
      5. 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查询 扩展增强 (第九篇)的更多相关文章

  1. EF下lambda与linq查询&&扩展方法

    1. linq查询数据 WebTestDBEntities db = new WebTestDBEntities(); 1.1 linq查询所有列数据 var userInfoList = from ...

  2. NHibernate3剖析:Query篇之NHibernate.Linq增强查询

    系列引入 NHibernate3.0剖析系列分别从Configuration篇.Mapping篇.Query篇.Session策略篇.应用篇等方面全面揭示NHibernate3.0新特性和应用及其各种 ...

  3. NHibernate系列文章二十四:NHibernate查询之Linq查询(附程序下载)

    摘要 NHibernate从3.0开始支持Linq查询.写Linq to NHibernate查询就跟写.net linq代码一样,非常灵活,可以很容易实现复杂的查询.这篇文章使用Linq to NH ...

  4. NHibernate 数据查询之Linq to NHibernate

    刚学NHibernate的时候觉得,HQL挺好用的,但是终归没有与其他技术相关联,只有NHibernate用到,一来容易忘记,二来没有智能提示,排除错误什么的都不给力,直到看到一个同事用Linq to ...

  5. NHibernate 数据查询之Linto to NHibernate (第八篇)

    NHibernate 数据查询之Linto to NHibernate (第八篇) 刚学NHibernate的时候觉得,HQL挺好用的,但是终归没有与其他技术 相关联,只有NHibernate用到,一 ...

  6. C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询

    1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...

  7. ElasticSearch入门 第九篇:实现正则表达式查询的思路

    这是ElasticSearch 2.4 版本系列的第九篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 E ...

  8. LINQ之路 5:LINQ查询表达式

    书写LINQ查询时又两种语法可供选择:方法语法(Fluent Syntax)和查询表达式(Query Expression). LINQ方法语法的本质是通过扩展方法和Lambda表达式来创建查询.C# ...

  9. 转:LINQ查询返回DataTable类型

    动态绑定ReportViewer虽然之前实现过,但现在弄起来还是有点晕,主要是过去没有使用Linq,数据的操作经常用到DataTable,可以直接拿来使用,现在用Linq更方便,也懒得再用之前的数据库 ...

随机推荐

  1. python基础===如何优雅的写代码(转自网络)

    本文是Raymond Hettinger在2013年美国PyCon演讲的笔记(视频, 幻灯片). 示例代码和引用的语录都来自Raymond的演讲.这是我按我的理解整理出来的,希望你们理解起来跟我一样顺 ...

  2. python基础===一道小学奥数题的解法

    今早在博客园和大家分享了一道昨晚微博中看到的小学奥数题,后来有朋友给出了答案.然后我尝试用python解答它. 原题是这样的: 数学题:好事好 + 要做好 = 要做好事,求 “好.事.做.要”的值分别 ...

  3. Python 如何将字符串转为字典

    在工作中遇到一个小问题,需要将一个 python 的字符串转为字典,比如字符串: user_info = '{"name" : "john", "ge ...

  4. Kotlin 学习使用之旅(二)

    为什么从二开始呢?再此之前已经有了一篇了,那是刚知道kotlin的时候草(chao)来(chao)的并且学习一篇, 这次是自己在项目中正式使用并且遇到的一些问题记录,供kotlin新入门的童鞋参考,避 ...

  5. 2017多校第8场 HDU 6133 Army Formations 线段树合并

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6133 题意:给你一棵n个节点的二叉树,每个节点有一个提交任务的时间,每个节点总的提交任务的罚时为:提交 ...

  6. 【软件设计】UML类图怎么看

    前言 无论使用哪种语言,都离不开面向过程与面向对象两个流派,而类图是面向对象程序设计中至关重要的一种软件表达形式,如何看懂类图,并设计好的软件架构,是我们作为软件工程师必不可少的技能之一. 今天小黑把 ...

  7. 2.ubuntu的使用

    1. CTRL+ALT+T 可以将命令模式打开 2. 有可能没办法进行yum ,它会告诉你操作的方法 3. 有些操作需要获得root的权限才可以,我们得进入root状态 --> sudo pas ...

  8. ZOJ-3318

    Strange Country Time Limit: 1 Second      Memory Limit: 32768 KB There are n cities in the dream cou ...

  9. MySQL建立高性能索引策略

    索引永远是最好的查询解决方案嘛? 索引并不总是最好的工具.总的来说,只有当索引帮助存储引擎快速查找到记录带来的好处大于其带来的额外工作(比如插入操作后索引的维护)时,索引才是高效的. 对于非常小的表: ...

  10. Subsets I&&II——经典题

    Subsets I Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a s ...