一步步学习NHibernate(4)——多对一,一对多,懒加载(1)
请注明转载地址:http://www.cnblogs.com/arhat
通过上一章的学习,我们学会如何使用NHibernate对数据的简单查询,删除,更新和插入,那么如果说仅仅是这样的话,那么NHibenrate的优势有在哪里呢?那么今天就要和大家一起来分享一下NHibernate的优势——懒加载(初探)。
我们知道,在关系数据库中,表和表之间是有联系的,那么通常情况下,我们通过连接查询能够把相关的数据查询处理,只是连接语句似乎大概写起来似乎是有些繁琐的,那么NHibenrate为我们提供了一种变相的操作,可以使这种连接查询变得简单多了。
现在呢,我们更改一下数据库,在数据库中我们新建一个表Clazz(班级表),并插入相关的数据。

同时,我们得更改一下Student表,在Student表中加入一个外键Cid,我们知道,学生和班级之间是存在者关系的。我们从两个方面来说:
对于Clazz:一个班级对应多个属性就是一对多的关系(one-to-many),是one的一方
对于Student:多个学生对应一个班级就是多对一的关系(mand-to-one),是many的一方
所以,我们需要对Student表中建立一个和Clazz对应的外键

好,现在我们清空一下Student中数据。
下面就是一个重点了,我们需要改写一下Student实体类和添加一个Clazz实体类。由于Student是Clazz的外键表,所以,我们应该这样改写Student实体类,在Student实体类中添加一个属性为Clazz,用来获得这个学生对应的班级,代码如下:
public class Student
{
public virtual int SId { get; set; }
public virtual string SName { get; set; }
public virtual string SSex { get;set; }
public virtual DateTime SBirthday{get;set;}
public virtual Clazz Clazz { get; set; }
}
然后添加Clazz类,代码如下
public class Clazz
{ public virtual int CId { get; set; } public virtual string CName { get; set; } public virtual ISet<Model.Student> Students { get; set; } }
由于,Clazz和Student是多对一的关系,所以在Clazz中需要定义一个集合属性,用来获得这个班级中的学生。这里使用的集合是Iesi.Collections.Generic.ISet类型。那么需要在Model项目中添加Iesi.Collections.dll的引用。
但是我们虽然更改了实体类的属性,但是NHibernate却不知道他们之间的关系,所以我们需要更改Student.hbm.xml和Clazz.hbm.xml映射文件,使NHibernate能够知道他们之间的关系。
Student.hbm.xml内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping assembly="Model" namespace="Model" xmlns="urn:nhibernate-mapping-2.2">
<class name="Student" table="Student">
<id name="SId" type="int">
<column name="sid"></column>
<generator class="native"></generator>
</id>
<property name="SName" type="string">
<column name="sname"/>
</property>
<property name="SSex" type="string">
<column name="ssex"/>
</property>
<property name="SBirthday" type="DateTime">
<column name="sbirthday"/>
</property>
<many-to-one name="Clazz" column="CId" class="Model.Clazz"></many-to-one>
</class>
</hibernate-mapping>
在Student.hbm.xml中,我们添加了一个<many-to-one>的节点,这个节点是用来说明在Student中Clazz属性是一个外键。其中name是Student中Clazz属性的属性名,column是Student表中的外键字段名,class是用来设置和Student关联的对象的完整名字(命名空间+类名)。
然后,我们看一下Clazz.hbm.xml的文件内容。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping assembly="Model" namespace="Model" xmlns="urn:nhibernate-mapping-2.2">
<class name="Clazz" table="clazz" lazy="true">
<id name="CId" type="int">
<column name="cid"></column>
<generator class="native"></generator>
</id>
<property name="CName" type="string">
<column name="cname"></column>
</property>
<set name="Students" table="student">
<key column="Cid"></key>
<one-to-many class="Model.Student"/>
</set>
</class>
</hibernate-mapping>
大家可以看到,由于在Clazz实体类中我们定义了一个集合属性,那么也就是表示了Clazz和Sutdent之间的多对一关系。那么自在Clazz.hbm.xml映射文件中,需要通过<set>节点来声明这个属性。其中<Set>节点中的name是Clazz中的集合属性名,table是指对应着数据库的那个表。其中<set>节点中有两个子节点<key>是用来说明Student表中的外键字段,<ono-to-many>是用来说明班级和学生之间的一对多关系,class属性是指和Clazz关联的Student的全类名。
一旦这两个映射文件通过<many-to-one>和<one-to-many>的设置,那么NHibenrate就知道了Student和Clazz之间的关系了。
由于在Student表中没有数据,我们现在插入几条数据来做测试。

然后,我们得做两个测试,才能说明NHibernate给我提供的懒加载机制以及测试中的问题。现在我们更改一下D_User.cs的代码
public Model.Student GetUser(int id)
{ //using(ISession session = NHibernateHelper.OpenSession()) //{ // return session.Get<Model.Student>(id); //} //} ISession session = NHibernateHelper.OpenSession(); { return session.Get<Model.Student>(id); } }
现在老魏有一个要求,就是要查找一下id=1学生的姓名和所在的班级名称。那么如果在SQL中,我们得使用一个连接语句,但是在NHibernate中一切将会变得简单多了。
然后,我们在主程序中更改一下代码:
DAL.D_User dal = new DAL.D_User();
Model.Student student = dal.GetUser(1);
Console.WriteLine("学生:"+student.SName+",所在的班级是:"+student.Clazz.CName);
运行一下,看看结果如何

我们发现,的确查询出了正确的结果。那么在执行的时候,NHibernate发出了两条SQL语句,那么大家可以看出,一个是查询Student的语句,一个是查询班级的SQL语句,那么现在我们的问题就来了,为什么NHibernate会发出两条语句呢。我们来测试一下,我们把:
Console.WriteLine("学生:"+student.SName+",所在的班级是:"+student.Clazz.CName);
给更改一下,只输出学生的姓名。我们会发现NHibernate只发出了一条SQL语句。

那么这是为什么呢?原来是NHibernate在做查询的时候,只是把数据Student表的数据查询出来了,反而和它关联的Clazz数据并没有查询出来。但是如果我们把注释去掉,在运行的时候,会发现NHibernate发出两条语句,而第二条语句就是用来查询和Student关联的Clazz属性的。这是为什么呢?这个原因就是在NHibernate默认情况下是启用懒加载机制的,那么什么是懒加载呢?
懒加载,我们认为是在需要的时候才开始执行,不需要的时候就不执行。那上面我们的测试结果已经说明这个问题了,当我们只是查询Student的基本信息时,它就只查询Student信息,但是现在由于我们不紧要显示Student的基本信息,还要显示班级信息,那么在显示完Student信息之后,发现有一句话:student.Clazz.CName。那么NHibenrate就会知道:”哦,现在你需要你的班级信息了,那好吧,我把班级信息查询出来,并班Clazz的信息创建一个对象,把这个对象赋值给Student的Clazz属性吧”。此时,NHibenrate就会向数据库发送一条SQL语句来查询Clazz的信息。
从上面我么可以看出,NHinberate的最大优点就是拥有的懒加载,使我们的查询变得简单起来了。
下面我们得做第二实验,D_User代码如下:
public Model.Student GetUser(int id)
{ using(ISession session = NHibernateHelper.OpenSession()) { return session.Get<Model.Student>(id); } } //ISession session = NHibernateHelper.OpenSession(); //{ // return session.Get<Model.Student>(id); //} }
这回呢,我们使用using语句来释放ISession资源。主程序代码不变,我们来看看运行的结果:

出错了,报了一个异常”no Session”。这是为什么呢?因为我们使用using语句来强制释放ISession的资源,而这个时候只能查询出Student的基本信息,反而查询不到了和它关联的Clazz西信息,原因很简单,就是懒加载的执行需要ISession在没有释放的前提下才能够执行的,所以我们一旦释放了ISession的资源,则懒加载是不起作用的。那么看到这里,大家可以想到,这是懒加载的问题,那么如果我们不使用懒加载不就可以了吗?我们来做一下实验。把Student.hbm.xml和Clazz.hbm.xml的<class>节点中取消懒加载,代码如下:
<class name="Clazz" table="clazz" lazy="false"> <class name="Student" table="Student" lazy="false">
然后我们运行一下程序,看看结果如何:

的确查询出来了,但是我么看看SQL语句,此时的SQL语句是一个连接查询,当然从性能上看基本上没有什么影响,因为这是从many这一段发起的。如果从one那一短发起,那就大大不同了,至于为什么,我们在下一章中来讨论。
我们会发现,如果我们取消了懒加载,那么结果是正确的,这就叫“立即执行”。但是,如果没有了懒加载的话,那么我们在写程序的时候会非常的难受,因为我们感受到懒加载给我们带来的好处,一般情况下,我们在使用完ISession之后要释放资源的。所以这里就出现一个矛盾,我们既要释放资源,也要使用懒加载,那么该怎么办呢?请看下章!
一步步学习NHibernate(4)——多对一,一对多,懒加载(1)的更多相关文章
- 一步步学习NHibernate(5)——多对一,一对多,懒加载(2)
请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们建立了Student和Clazz之间的关联属性,并从Student(many)的一方查看了Clazz的信 ...
- MyBatis --- 映射关系【一对一、一对多、多对多】,懒加载机制
映射(多.一)对一的关联关系 1)若只想得到关联对象的id属性,不用关联数据表 2)若希望得到关联对象的其他属性,要关联其数据表 举例: 员工与部门的映射关系为:多对一 1.创建表 员工表 确定其外键 ...
- 【IOS学习基础】weak和strong、懒加载、循环引用
一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...
- webpack学习笔记—优化缓存、合并、懒加载等
除了前面的webpack基本配置,还可以进一步添加配置,优化合并文件,加快编译速度.下面是生产环境配置文件webpack.production.js,与wenbpack.config.js相比其不需要 ...
- 一步步学习NHibernate(6)——ISession的管理
请注明转载地址:http://www.cnblogs.com/arhat 今天老魏那个汗啊,我的ThinkPad的电源线不通电了,擦啊.明天还得掏银子买一个!心疼啊,原装的啊.不过话说回来,已经用了将 ...
- 一步步学习NHibernate(8)——HQL查询(2)
请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏带着大家学习了HQL语句,发现HQL语句还是非常不错的,尤其是在懒加载的时候,书写起来比较的舒服,但是这里老魏 ...
- EF Code First 一对多、多对多关联,如何加载子集合?
应用场景 先简单描述一下标题的意思:使用 EF Code First 映射配置 Entity 之间的关系,可能是一对多关系,也可能是多对多关系,那如何加载 Entity 下关联的 ICollectio ...
- MyBatis加强(1)~myBatis对象关系映射(多对一关系、一对多关系)、延迟/懒加载
一.myBatis对象关系映射(多对一关系.一对多关系) 1.多对一关系: ---例子:多个员工同属于一个部门. (1)myBatis发送 额外SQL: ■ 案例:员工表通过 dept_id 关联 部 ...
- 【Java EE 学习 47】【Hibernate学习第四天】【sesion】【一级缓存】【懒加载】
一.Session概述 1.Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法. 2.理解Sessi ...
随机推荐
- Hibernate初级
文章来源: http://blog.csdn.net/jiuqiyuliang/article/details/39078749/ 持久化(Persistence),把数据(如内存中的对象)保存到可永 ...
- 命令行界面下用户和组管理之userdel的使用
userdel - delete a user account and related files 在Linux中,userdel命令的功能是删除系统中的用户及相关的文件 语法 userdel ...
- 关于增强for循环
1 增强for循环增强for循环是for的一种新用法!用来循环遍历数组和集合. 1.1 增强for的语法for(元素类型 e : 数组或集合对象) {}例如:int[] arr = {1,2,3};f ...
- 关于Eclipse中的快捷键占用的解决.
刚进公司用的之前离职员工的电脑,打开Eclipse经常用的一个alt+/ 内容提示快捷键就是不好使. 让同事帮忙之后才发现原因. 在eclipse中快捷键设置是在 windows---->pr ...
- 非XA式Spring分布式事务
Spring应用的几种事务处理机制 Java Transaction API和XA协议是Spring常用的分布式事务机制,不过你可以选择选择其他的实现方式.理想的实现取决于你的应用程序使用何种资源,你 ...
- [转载][jQuery] Cannot read property ‘msie’ of undefined错误的解决方法
参考 [jQuery] Cannot read property ‘msie’ of undefined错误的解决方法 ---------------------------------------- ...
- Windows服务定时运行,判断当前时间是否在配置时间段内
/// <summary> /// 判断程序是否在设置运行时间内 /// </summary> /// <param name="startTime" ...
- EL表达式简单应用
<%@page import="java.util.HashMap"%> <%@page import="java.util.List"%&g ...
- 利用html模板生成Word文件(服务器端不需要安装Word)
利用html模板生成Word文件(服务器端不需要安装Word) 由于管理的原因,不能在服务器上安装Office相关组件,所以只能采用客户端读取Html模板,后台对模板中标记的字段数据替换并返回给客户端 ...
- 【转】prototype扩展的JavaScript常用函数库
Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> ...