一步步学习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 ...
随机推荐
- 导入MyEclipse项目乱码
1.右键项目属性→text file encoding →修改为UTF-8,即可自动变成正常的.
- Forwarding a Range of Ports in VirtualBox
STAN SCHWERTLY MAY 9, 2012 ARTICLES 3 COMMENTS Doesn't allow forwarding a range of ports through the ...
- Oracle inactive session (last_call_et)
注意last_call_et的值, select s.status,s.last_call_et,s.* from v$session s where username='DDD'; 在本例中,开了个 ...
- Lucene全文检索系列(一)
1. Lucene简介 Lucene是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎.Lucene以其方便使用.快速实施以及灵活性受到广泛的关注.它可以方便地嵌入到各种应用中实现针对应用的全文 ...
- [置顶] Objective-C开发环境介绍以及Cocoa,以及第一个程序
Objective-C 起源与发展 Brad J. Cox designed the Objective-C language in the early 1980 . 布兰德于1980年设计的 ...
- 关于Eclipse中的开源框架EMF(Eclipse Modeling Framework)
Eclipse项目本身可以划分为4个主要的子项目:Equinox,平台,Java开发工具(Java Development Tools,JDT)和插件开发环境(Plug-in Development ...
- 使用jQuery获取Bootstrap Switch的值
$('#switcher').bootstrapSwitch('state'); // true || false $('#switcher').bootstrapSwitch('toggleStat ...
- highcharts 去掉右下角链接
去掉右下角的highcharts.com链接需要加入以下代码: credits: { enabled:false }, 如果不设置,那么默认为显示.
- xml约束DTD演示
此演示xml和DTD在一个文件中 book.xml <?xml version="1.0" encoding="utf-8"?> <!DOCT ...
- JAXB - XML Schema Types, Defining Types for XML Elements Without Content
Types for XML elements are constructed using xsd:complexType, even if they do not have content. The ...