NHibernate从入门到精通系列(8)——一对一关联映射
来源:互联网 发布:斯芬克 知乎 编辑:程序博客网 时间:2024/06/05 03:27
内容摘要
单向主键关联映射
双向主键关联映射
唯一外键关联映射
NHibernate的一对一关联映射有三种,单向主键关联映射、双向主键关联映射、唯一外键关联映射。
一、单向主键关联映射
我们模拟一个现实情况:学生(Student)和家庭(Family)的关系。在中国,目前实行计划生育,一个家庭只有一个孩子,孩子上学后就成为了学生。学生和家庭的关系可以认为是一对一的。
让我们看一下“一对一”的表结构,如图1.1所示:
图1.1
让我们看一下“一对一”的实体类和映射文件:
public class Student { public virtual int? ID { get; set; } public virtual string Name { get; set; } } public class Family { public virtual int? ID { get; set; } public virtual string Adress { get; set; } public virtual Student Student { get; set; } }
<class name="Student" table="T_Student" lazy="true" > <id name="ID" column="StudentID" type="int"> <generator class="native"/> </id> <property name="Name" type="string" length="50"/> </class> <class name="Family" table="T_Family" lazy="true" > <id name="ID" column="FamilyID" type="int"> <generator class="foreign"> <param name="property">Student</param> </generator> </id> <property name="Adress" type="string" length="200"/> <one-to-one name="Student" constrained="true"/> </class>
其中,我们设置了“Family”类的主键生成策略为:“foreign”,含义是通过外键查询到主键值。
param的name属性设置为property,值设置为“Student”,表示通过“Student”属性查询到主键值。
然后使用<one-to-one>标签来描述“一对一”关联映射,并设置constrained属性为true,来建立一个外键约束。
环境建立好了,生成的表结构,如图1.2所示,我们能够观察到“T_Family”表的“FamilyID”字段既是主键又是外键。
图1.2
我们编写单元测试类的代码测试一下插入和查询。
[TestFixture] public class DomainTest { private ISessionFactory sessionFactory; [SetUp] public void InitTest() { var cfg = new NHibernate.Cfg.Configuration().Configure("Config/hibernate.cfg.xml"); sessionFactory = cfg.BuildSessionFactory(); } [Test] public void SaveFamilyTest() { using (ISession session = this.sessionFactory.OpenSession()) { var student = new Student { Name = "刘冬" }; var family = new Family { Adress = "新疆乌鲁木齐市", Student = student }; ITransaction tran = session.BeginTransaction(); try { session.Save(family); tran.Commit(); } catch (Exception ex) { tran.Rollback(); throw ex; } } } [Test] public void SelectFamilyTest() { using (ISession session = this.sessionFactory.OpenSession()) { var family = session.CreateQuery("from Family").List<Family>().First(); Console.WriteLine("家庭地址为:{0}", family.Adress); Console.WriteLine("学生姓名为:{0}", family.Student.Name); } } }
插入的运行效果如图1.3所示,运行成功。奇怪的是,“Family”引用了一个临时态(Transient)的实例“Student” ,但并没有抛出异常。
这是因为<one-to-one>默认的cascade为all,这样NHibernate自动帮助我们把临时态(Transient)的实例持久化到数据库中了。
图1.3
查询的运行效果如图1.4所示,通过关联的属性带出了想要的信息。
图1.4
二、双向主键关联映射
我们修改一下代码,来体现双向主键关联映射:在“Student”类中加入属性“Family”,这样“Student”中有“Family”,“Family”中也有“Student”的循环引用方式就描述了双向主键关联映射的实体类结构。
然后在“Student”的映射文件中加入“<one-to-one name="Family" class="Family"/>”。
public class Student { public virtual int? ID { get; set; } public virtual string Name { get; set; } public virtual Family Family { get; set; } }
<class name="Student" table="T_Student" lazy="true" > <id name="ID" column="StudentID" type="int"> <generator class="native"/> </id> <property name="Name" type="string" length="50"/> <one-to-one name="Family" class="Family"/> </class>
然后编写一个查询的单元测试方法:
[Test] public void SelecStudentTest() { using (ISession session = this.sessionFactory.OpenSession()) { var student = session.Get<Student>(1); Console.WriteLine("学生姓名为:{0}", student.Name); Console.WriteLine("家庭地址为:{0}", student.Family.Adress); } }
运行效果如图2.1所示。奇怪的是仅生成了一条SQL语句就将两个表中的数据获取出来了。这是因为“一对一”主键关联映射默认的抓取(fetch)策略是“join”。
图2.1
三、唯一外键关联映射
唯一外键关联映射是非主键字段的“一对一”关联。
我们模拟一种“一对一”情况:一个班级对应了一个班主任老师,一个班主任老师管理一个班级。代码如下:
public class Class { public virtual int? ID { get; set; } public virtual string Name { get; set; } /// <summary> /// 班主任老师 /// </summary> public virtual Teacher Teacher { get; set; } } public class Teacher { public virtual int? ID { get; set; } public virtual string Name { get; set; } public virtual Class Class { get; set; } }
<class name="Class" table="T_Class" > <id name="ID" column="ClassID" type="int"> <generator class="native"/> </id> <property name="Name" type="string" length="50"/> <many-to-one name="Teacher" class="Teacher" column="TeacherID" unique="true"/> </class> <class name="Teacher" table="T_Teacher"> <id name="ID" column="TeacherID" type="int"> <generator class="native"/> </id> <property name="Name" type="string" length="50"/> <one-to-one name="Class" class="Class" property-ref="Teacher"/> </class>
我们在“Class”类中使用<many-to-one>标签,并设置unique属性为true。然后在“Teacher”类中使用<one-to-one>标签,并设置属性“Class”的property-ref指向“Teacher”。
最后编写一个单元测试方法:
[Test] public void SaveTeacherTest() { using (ISession session = this.sessionFactory.OpenSession()) { var teacher = new Teacher { Name = "刘冬" }; var cls = new Class { Name = "1班", Teacher = teacher }; teacher.Class = cls; ITransaction tran = session.BeginTransaction(); try { session.Save(teacher); session.Save(cls); tran.Commit(); } catch (Exception ex) { tran.Rollback(); throw ex; } } }
运行效果如图3.1所有,运行成功。
图3.1
然后观察生成的表结构,如图3.2所示,生成了唯一外键。
图3.2
但注意的是:唯一外键关联映射实际上使用的是<many-to-one>标签,所有说默认的cascade是“none”,这样必须确保在没有引用临时态(Transient)的实例下才能持久化数据。
- NHibernate从入门到精通系列(8)——一对一关联映射
- NHibernate从入门到精通系列(7)——多对一关联映射
- NHibernate从入门到精通系列(9)——一对多关联映射
- NHibernate从入门到精通系列(10)——多对多关联映射
- NHibernate从入门到精通系列(6)——基本映射
- NHibernate从入门到精通系列(6)——基本映射
- NHibernate一对多单双向关联映射-NHibernate入门到精通系列9
- NHibernate多对多单双向关联映射-NHibernate入门到精通系列10
- 【Hibernate】从入门到精通(五)关联映射之一对一映射
- NHibernate从入门到精通系列(1)——NHibernate概括
- NHibernate从入门到精通系列(2)——NHibernate环境与结构体系
- NHibernate从入门到精通系列(1)——NHibernate概括
- NHibernate从入门到精通系列(2)——NHibernate环境与结构体系
- NHibernate从入门到精通系列(3)——第一个NHibernate应用程序
- NHibernate从入门到精通系列(1)——NHibernate概括
- NHibernate从入门到精通系列(1)——NHibernate概括
- NHibernate从入门到精通系列(2)——NHibernate环境与结构体系
- NHibernate从入门到精通系列
- 容器类——记事本
- linux下的OpenCV安装&学习笔记
- html 和 css
- 剑指 offer:矩形覆盖
- 对象的初始化过程
- NHibernate从入门到精通系列(8)——一对一关联映射
- Linux下设置发邮件
- extract用法
- 线程等待的几种方式
- iOS 开发之 菜单栏UITabBarController
- 删除表空间报错ORA-00604&ORA-02429解决过程
- Android View坐标getLeft, getRight, getTop, getBottom解惑
- android intent
- 播放视频VideoView和SurfaceView(它是父类)(查看api)(更高级的查看vitamio)