请注明转载地址: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)的更多相关文章

  1. 一步步学习NHibernate(5)——多对一,一对多,懒加载(2)

    请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们建立了Student和Clazz之间的关联属性,并从Student(many)的一方查看了Clazz的信 ...

  2. MyBatis --- 映射关系【一对一、一对多、多对多】,懒加载机制

    映射(多.一)对一的关联关系 1)若只想得到关联对象的id属性,不用关联数据表 2)若希望得到关联对象的其他属性,要关联其数据表 举例: 员工与部门的映射关系为:多对一 1.创建表 员工表 确定其外键 ...

  3. 【IOS学习基础】weak和strong、懒加载、循环引用

    一.weak和strong 1.理解 刚开始学UI的时候,对于weak和strong的描述看得最多的就是“由ARC引入,weak相当于OC中的assign,但是weak用于修饰对象,但是他们都不会造成 ...

  4. webpack学习笔记—优化缓存、合并、懒加载等

    除了前面的webpack基本配置,还可以进一步添加配置,优化合并文件,加快编译速度.下面是生产环境配置文件webpack.production.js,与wenbpack.config.js相比其不需要 ...

  5. 一步步学习NHibernate(6)——ISession的管理

    请注明转载地址:http://www.cnblogs.com/arhat 今天老魏那个汗啊,我的ThinkPad的电源线不通电了,擦啊.明天还得掏银子买一个!心疼啊,原装的啊.不过话说回来,已经用了将 ...

  6. 一步步学习NHibernate(8)——HQL查询(2)

    请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏带着大家学习了HQL语句,发现HQL语句还是非常不错的,尤其是在懒加载的时候,书写起来比较的舒服,但是这里老魏 ...

  7. EF Code First 一对多、多对多关联,如何加载子集合?

    应用场景 先简单描述一下标题的意思:使用 EF Code First 映射配置 Entity 之间的关系,可能是一对多关系,也可能是多对多关系,那如何加载 Entity 下关联的 ICollectio ...

  8. MyBatis加强(1)~myBatis对象关系映射(多对一关系、一对多关系)、延迟/懒加载

    一.myBatis对象关系映射(多对一关系.一对多关系) 1.多对一关系: ---例子:多个员工同属于一个部门. (1)myBatis发送 额外SQL: ■ 案例:员工表通过 dept_id 关联 部 ...

  9. 【Java EE 学习 47】【Hibernate学习第四天】【sesion】【一级缓存】【懒加载】

    一.Session概述 1.Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法. 2.理解Sessi ...

随机推荐

  1. Android 换肤功能的实现(Apk插件方式)

    一.概述 由于Android 没有提供一套统一的换肤机制,我猜可能是因为国外更注重功能和体验的原因 所以国内如果要做一个漂亮的换肤方案,需要自己去实现. 目前换肤的方法大概有三种方案: (1)把皮肤资 ...

  2. 有效范围为request的bean

    Car.java类 package tom.jiafei; public class Car { String carnumber; String name; String date; public ...

  3. iOS之Git的使用

    1.登录Git账号,创建一个新的仓库

  4. httpURLConnection-网络请求的两种方式-get请求和post请求

    GET请求 /** * 从网络获取json数据,(String byte[}) * @param path * @return */ public static String getJsonByInt ...

  5. JavaScript总结1

    一.JavaScript变量类型.声明.作用域 1.1 数字 number 小数和整数都叫number,以0x或0X开头的表示十六进制.当无穷大时,用Infinity表示(试试 9/0),其他非数字用 ...

  6. linux__升级java版本

    java下载地址:http://www.oracle.com/index.html 使用which java查看到,Java的环境变量指向的还是/usr/bin/java,问题找到了.于是就进行了下面 ...

  7. Java双向链表实现

    public class DoublyLinkList { private class Data{ private Object obj; private Data left = null; priv ...

  8. dedecms安装步骤

    GD支持:PHP设置-PHP扩展-php_gd2 初始化数据体验包:点击下载:或者点击取消     如果是本地安装在数据库的在数据库用户名选择默认的(root),密码为空 主要是如果是基于远程服务器的 ...

  9. Entity Framework 学习整理(分播客整理)

    MSDN: http://msdn.microsoft.com/en-us/data/aa937723 台湾博客: http://www.dotblogs.com.tw/yc421206/ http: ...

  10. ASP.Net Core 运行在Linux(Ubuntu)

    这段时间一直在研究asp.net core部署到linux,今天终于成功了,这里分享一下我的部署过程. Linux Disibutaion:Ubuntu 14.04 Web Server:nginx. ...