NHibernate Linq查询 扩展增强 (第九篇)
2015-12-09 09:55
183 查看
NHibernate Linq查询 扩展增强 (第九篇)
在上一篇的Linq to NHibernate的介绍当中,全部是namespace NHibernate命名空间中的IQueryOver<TRoot, TSubType>接口提供的。IQueryOver<TRoot, TSubType>这个借口实际上会被翻译成条件查询(Criteria Queries)。
实际上Linq to NHibernate更加强大。我们先引入命名空间NHibernate.Linq,这里面有Linq to NHibernate更强大的扩展。
延迟加载产生的SQL执行方式:
执行结果为:
![](http://images.cnitblog.com/blog/347600/201309/16230141-21ddc7f006e243f9ab3bfa336b8cee22.jpg)
这延迟加载玩大发了吧。foreach()一次,读一条记录,这... 看到上面语句的FROM Country了吗,其实主要是读Person的时候没有把Country也读出来,弄得每次foreach()的时候必须在到数据库读取Person对 应的Country造成的,如果我们不想因为跨表查询到Country就要在加载的时候,把Person所对应的Country也加载过来。
立即加载,还好,有Fetch方法,我们来看看如下代码:
执行的SQL语句为:
![](http://images.cnitblog.com/blog/347600/201309/16230515-6ce06ca77eca488cb85b2be99c5676df.jpg)
这个还像话,就应该这样吗。NHibernate默认开启延迟加载特性,以便其他查询顺利应用延迟加载带来的益处。而当我们不希望延迟加载的时 候,可以通过Fetch()编程的方式控制。不错。以上程序,Fetch的作用是加载Person时,强制加载与Person关联的Country。
下面再来说说立即加载一些其他的东西,我们将原来的数据库改成如下:
![](http://images.cnitblog.com/blog/347600/201309/17090344-0d9e8441b94843a2bfc2c7f8a1304f59.jpg)
1、多个关联
Person除了有一个所属国家外,还有一个所属学校。那么我们要输出一个Person的CountryName与SchoolName。又应该怎么处理呢?
我们得Fetch().Fetch()把数据一次性加载过来,否则还是会出现foreach()一次,查询一次School的情况。
以上代码输出如下:
![](http://images.cnitblog.com/blog/347600/201309/17090648-64830586875f4209b60928173f23c011.jpg)
2、嵌套关联
在上一节的图中,Person属于Country,而Country又属于一个Area。如果我们Fetch()了Country,那么如果要 输出AreaName还是要再次查数据库。因此,我们希望在读取Perosn时,顺带读出关联的Country,再顺带读出关联的Area怎么做到呢?
输出结果如下:
![](http://images.cnitblog.com/blog/347600/201309/17095220-00a7c4a88c384811ad693ed9b4693c18.jpg)
以上代码一次过读出所需的数据,毫不做作。
Fetch与FetchMany的区别
Fetch与FetchMany的区别与Select与SelectMany的区别一样。看了一下,方法签名,主要是有一个参数的区别。
留意到方法签名只是查了一点点,但是对于根据Area获取Country再获取Person来说,就非FetchMany不可了。因为Fetch()的参数不允许为集合。
例如,我们查出所有的地区,然后列出地区的所有国家,再列出所有的PersonName:
输出如下:
![](http://images.cnitblog.com/blog/347600/201309/18092012-fda6f554417f45d49574acd4dee0dd42.jpg)
区别在于FetchMany,ThenFetchMany接受IEnumerable<T>类型的数据输入,而Fetch,FetchMany不支持。
Cacheable 为一个查询显示启用二级缓存;
CacheMode 缓存模式, 有如下可选:
Ignore:更新数据时将二级缓存失效,其它时间不和二级缓存交互
Put:向二级缓存写数据,但不从二级缓存读数据
Get:从二级缓存读数据,仅在数据更新时向二级缓存写数据
Normal:默认方式。从二级缓存读/写数据
Refresh:向二级缓存写数据,想不从二级缓存读数据,通过在配置文件设置 cache.use_minimal_puts从数据库中读取数据时,强制二级缓存刷新
CacheRegion 给查询缓存指定了特定的命名缓存区域, 如果两个查询相同, 但是指定的 CacheRegion 不同, 则也会从数据库查询数据。
1、在使用缓存之前,先来开启NHibernate二级缓存。
2、在要使用缓存的实体类的映射文件上,Id节点前加上这一行:
然后,还是利用上面的例子来测试。
输出结果如下:
![](http://images.cnitblog.com/blog/347600/201309/18171926-9e991cd5669f4bbf8775b17b02061977.jpg)
这个没什么好说的了,看懂那3个方法的说明好了。
在上一篇的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(); }
执行结果为:
![](http://images.cnitblog.com/blog/347600/201309/16230141-21ddc7f006e243f9ab3bfa336b8cee22.jpg)
这延迟加载玩大发了吧。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语句为:
![](http://images.cnitblog.com/blog/347600/201309/16230515-6ce06ca77eca488cb85b2be99c5676df.jpg)
这个还像话,就应该这样吗。NHibernate默认开启延迟加载特性,以便其他查询顺利应用延迟加载带来的益处。而当我们不希望延迟加载的时 候,可以通过Fetch()编程的方式控制。不错。以上程序,Fetch的作用是加载Person时,强制加载与Person关联的Country。
下面再来说说立即加载一些其他的东西,我们将原来的数据库改成如下:
![](http://images.cnitblog.com/blog/347600/201309/17090344-0d9e8441b94843a2bfc2c7f8a1304f59.jpg)
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的情况。
以上代码输出如下:
![](http://images.cnitblog.com/blog/347600/201309/17090648-64830586875f4209b60928173f23c011.jpg)
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(); }
输出结果如下:
![](http://images.cnitblog.com/blog/347600/201309/17095220-00a7c4a88c384811ad693ed9b4693c18.jpg)
以上代码一次过读出所需的数据,毫不做作。
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); } } }
输出如下:
![](http://images.cnitblog.com/blog/347600/201309/18092012-fda6f554417f45d49574acd4dee0dd42.jpg)
区别在于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(); }
输出结果如下:
![](http://images.cnitblog.com/blog/347600/201309/18171926-9e991cd5669f4bbf8775b17b02061977.jpg)
这个没什么好说的了,看懂那3个方法的说明好了。
相关文章推荐
- springmvc jsp中的css,js路径正确,但浏览器无法找到
- 接口与抽象类
- 几种经典的hash算法
- spark streaming+flume avro实时计算
- 华为内部的Web安全原则
- Linux软件安装(rpm和yum)
- python 装饰器
- spring Context配置留着慢慢看
- [leetcode]Pascal's Triangle
- iOS_UITextView _ 链接地址在应用程序内跳转 _ 占位符 _ 改变选中文本的属性
- Map集合
- Block学习一门:基本使用,使用block包NSURLRequest异步请求
- 如何获取Window对象
- NHibernate 操作视图 第十三篇
- 夺命雷公狗---javascript NO:15 事件冒泡3
- Linux环境下忘记mysql密码处理方法
- Errors running builder "Integrated External Tool Builder" on project
- 网络营销包含哪些方面的知识听太原郭文军细讲
- Java -- 通过反射处理bean对象
- Web Dynpro ABAP---ALV控件的使用