一、 一对一关联映射

²        两个对象之间是一对一的关系,如Person-IdCard(人—身份证号)

²        有两种策略可以实现一对一的关联映射

Ø        主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联。

Ø        唯一外键关联:外键关联,本来是用于多对一的配置,但是如果加上唯一的限制之后,也可以用来表示一对一关联关系。

对象模型

实体类:

/** 人-实体类 */

public class Person {

private int id;

private String name;

public int getId() {return id;  }

public void setId(int id) {this.id = id;}

public String getName() {return name;}

public void setName(Stringname) {this.name = name;}

}

/**身份证-实体类*/

public class IdCard {

private int id;

private String cardNo;

public int getId() {return id;}

public void setId(int id) {this.id = id;}

public String getCardNo(){ return cardNo;}

public void setCardNo(StringcardNo) {this.cardNo = cardNo;}

}

(一) 唯一外键关联-单向(unilateralism)

1、 说明:

人—-> 身份证号(PersonàIdCard),从IdCard看不到Person对象

2、 对象模型

需要在Person类中持有IdCard的一个引用idCard,则IdCard中没有Person的引用

3、 关系模型

关系模型目的:是实体类映射到关系模型(数据库中),是要求persion中添加一个外键指向idcard

4、 实体类:

注:IdCard是被引用对象,没有变化。

/** 人-实体类 */

public class Person {

private int id;

private String name;

private IdCard idCard;//引用IdCard对象

public int getId() {return id;  }

public void setId(int id) {this.id = id;}

public String getName() {return name;}

public void setName(String name){this.name = name;}

public IdCard getIdCard() { return idCard;}

public void setIdCard(IdCardidCard) {this.idCard = idCard;}

}

5、 xml映射

IdCard实体类的映射文件:

因为IdCard是被引用的,所以没有什么特殊的映射

<hibernate-mapping>

<class name="com.wjt276.hibernate.IdCard" table="t_idcard">

<id name="id" column="id">

<generator class="native"/>

</id>

<property name="cardNo"/>

</class>

</hibernate-mapping>

Person实体类的映射文件

在映射时需要添加一个外键的映射,就是指定IdCard的引用的映射。这样映射到数据库时,就会自动添加一个字段并作用外键指向被引用的表

<hibernate-mapping>

<class name="com.wjt276.hibernate.Person" table="t_person">

<id name="id" column="id">

<generator class="native"/>

</id>

<property name="name"/>

<!-- <many-to-one>:在多的一端(当前Person一端),加入一个外键(当前为idCard)指向一的一端(当前IdCard),但多对一 关联映射字段是可以重复的,所以需要加入一个唯一条件unique="true",这样就可以此字段唯一了。-->

<many-to-one name="idCard" unique="true"/>

</class>

</hibernate-mapping>

注意:这里的<many-to-one>标签中的name属性值并不是数据库中的字段名,而是Person实体类中引用IdCard对象成员属性的getxxx方法后面的xxx(此处是getIdCard,所以是idCard),要求第一个字段小写。如果不指定column属性,则数据库中的字段名同name值

6、 annotateon注解映射

注意IdCard是被引用对象,除正常注解,无需要其它注解

/**身份证*/

@Entity

public class IdCard {

private int id;

private String cardNo;

@Id

@GeneratedValue

public int getId() {return id;}

public void setId(int id) { this.id = id;}

public String getCardNo(){return cardNo;}

public void setCardNo(StringcardNo) {this.cardNo = cardNo;}

}

而引用对象的实体类需要使用@OneToOne进行注解,来表面是一对一的关系

再使用@JoinColumn注解来为数据库表中这个外键指定个字段名称就可以了。如果省略@JoinColumn注解,则hibernate会自动为其生成一个字段名(好像是:被引用对象名称_被引用对象的主键ID)

/** 人-实体类 */

@Entity

public class Person {

private int id;

private IdCard idCard;//引用IdCard对象

private String name;

@Id

@GeneratedValue

public int getId() {return id;}

@OneToOne//表示一对一的关系

@JoinColumn(name="idCard")//为数据中的外键指定个名称

public IdCard getIdCard(){ return idCard;}

public String getName() {return name;}

public void setId(int id) {this.id = id;}

public void setIdCard(IdCardidCard) {this.idCard = idCard;}

public void setName(Stringname) {this.name = name;}

}

7、 生成的SQL语句:

create tableIdCard (

id integernot null auto_increment,

cardNo varchar(255),

primary key(id)

)

create tablePerson (

id integernot null auto_increment,

namevarchar(255),

idCardinteger,//新添加的外键

primary key(id)

)

alter tablePerson

add indexFK8E488775BE010483 (idCard),

addconstraint FK8E488775BE010483

foreign key(idCard) //外键

referencesIdCard (id)//引用IdCard的id字段

8、 存储测试

Session session = sf.getCurrentSession();

IdCard idCard = new IdCard();

idCard.setCardNo("88888888888888888888888");

session.beginTransaction();

// 如果先不保存idCard,则出抛出Transient异常,因为idCard不是持久化状态。

session.save(idCard);

Person person = new Person();

person.setName("菜10");

person.setIdCard(idCard);

session.save(person);

session.getTransaction().commit();

(二) 唯一外键关联-双向

1、 说明:

人<—-> 身份证号(Person<->IdCard)双向:互相持有对方的引用

2、 对象模型:

3、 关系模型:

关系模型没有任务变化,同单向

4、 实体类:

实体类,只是相互持有对象的引用,并且要求getter和setter方法

5、 xml映射

Person实体类映射文件:同单向的没有变化

IdCard实体类映射文件:如果使用同样的方法映射,这样就会在表中也添加一个外键指向对象,但对象已经有一个外键指向自己了,这样就造成了庸字段,因为不需要在表另外添加字段,而是让hibernate在加载这个对象时,会根据对象的ID到对方的表中查询外键等于这个ID的记录,这样就把对象加载上来了。也同样需要使用<one-to-one>标签来映射,但是需要使用property-ref属性来指定对象持有你自己的引用的成员属性名称(是gettxxxx后面的名称),这样在生成数据库表时,就不会再添加一个多于的字段了。数据加载时hibernate会根据这些配置自己加载数据

<class name="com.wjt276.hibernate.IdCard" table="idcard">

<id name="id" column="id">

<generator class="native"/></id>

<property name="cardNo"/>

<!--<one-to-one>标签:告诉hibernate如何加载其关联对象

property-ref属性:是根据哪个字段进行比较加载数据 -->

<one-to-one name="person" property-ref="idCard"/>

</class>

一对一 唯一外键 关联映射 双向 需要在另一端(当前IdCard),添加<one-to-one>标签,指示hibernate如何加载其关联对象(或引用对象),默认根据主键加载(加载person),外键关联映射中,因为两个实体采用的是person的外键来维护的关系,所以不能指定主键加载person,而要根据person的外键加载,所以采用如下映射方式:

<!--<one-to-one>标签:告诉hibernate如何加载其关联对象

property-ref属性:是根据哪个字段进行比较加载数据 -->

<one-to-one name="person" property-ref="idCard"/>

6、 annotateon注解映射

Person注解映射同单向一样

IdCard注解映射如下:使用@OneToOne注解来一对一,但这样会在表中多加一个字段,因为需要使用对象的外键来加载数据,所以使用属性mappedBy属性在实现这个功能

@Entity

public class IdCard {

private int id;

private String cardNo;

private Person person;

//mappedBy:在指定当前对象在被Person对象的idCard做了映射了

//此值:当前对象持有引用对象中引用当前对象的成员属性名称(getXXX后的名称)

//因为Person对象的持有IdCard对象的方法是getIdCard()因为需要小写,所以为idCard

@OneToOne(mappedBy="idCard")

public Person getPerson(){return person;}

public void setPerson(Person person){this.person = person;}

@Id

@GeneratedValue

public int getId() {return id;}

public void setId(int id) { this.id = id;}

public String getCardNo(){return cardNo;}

public void setCardNo(StringcardNo) {this.cardNo = cardNo;}

}

7、 生成SQL语句

因为关系模型没有变化,也就是数据库的结构没有变化,只是在数据加载时需要相互加载对方,这由hibernate来完成。因为生成的sql语句同单向一样

8、 存储测试

存储同单向一样

9、 总结:

规律:凡是双向关联,必设mappedBy

(三) 主键关联-单向(不重要)

主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联。

1、 说明:

人—-> 身份证号(PersonàIdCard),从IdCard看不到Person对象

2、 对象模型

站在人的角度来看,对象模型与唯一外键关联一个,只是关系模型不同

3、 关系模型

因为是person引用idcard,所以idcard要求先有值。而person的主键值不是自己生成的。而是参考idcard的值,person表中即是主键,同时也是外键

4、 实体类:

实体类同 一对一 唯一外键关联的实体类一个,在person对象中持有idcard对象的引用(代码见唯一外键关系)

5、 xml映射

IdCard映射文件,先生成ID

<class name="com.wjt276.hibernate.IdCard" table="t_idcard">

<id name="id"column="id">

<generator class="native"/>

</id>

<property name="cardNo"/>

</class>

Person实体类映射文件,ID是根据IdCard主键值   

<class name="com.wjt276.hibernate.Person"table="t_person">

<id name="id"column="id">

<!--因为主键不是自己生成的,而是作为一个外键(来源于其它值),所以使用foreign生成策略

foreign:使用另外一个相关联的对象的标识符,通常和<one-to-one>联合起来使用。再使用元素<param>的属性值指定相关联对象(这里Person相关联的对象为idCard,则标识符为idCard的id)为了能够在加载person数据同时加载IdCard数据,所以需要使用一个标签<one-to-one>来设置这个功能。  -->

<generator class="foreign">

<!-- 元素<param>属性name的值是固定为property -->

<param name="property">idCard</param>

</generator>

</id>

<property name="name"/>

<!-- <one-to-one>标签

表示如何加载它的引用对象(这里引用对象就指idCard这里的name值是idCard),同时也说是一对一的关系。 默认方式是根据主键加载(把person中的主键取出再到IdCard中来取相关IdCard数据。) 我们也说过此主键也作为一个外键引用 了IdCard,所以需要加一个数据库限制(外键约束)constrained="true"     -->

<one-to-one name="idCard"constrained="true"/>

6、 annotateon注解映射

Person实体类注解

方法:只需要使用@OneToOne注解一对一关系,再使用@PrimaryKeyJoinColumn来注解主键关系映射。

@Entity

public class Person {

private int id;

private IdCard idCard;//引用IdCard对象

private String name;

@Id

public int getId() {return id;}

@OneToOne//表示一对一的关系

@PrimaryKeyJoinColumn//注解主键关联映射

public IdCard getIdCard(){ return idCard;}

public String getName() {return name;}

public void setId(int id) {this.id = id;}

public void setIdCard(IdCard idCard){this.idCard = idCard;}

public void setName(Stringname) {this.name = name;}

}

IdCard实体类,不需要持有对象的引用,正常注解就可以了。

7、 生成SQL语句

生成的两个表并没有多余的字段,因为是通过主键在关键的

create tableIdCard (

id integernot null auto_increment,

cardNovarchar(255),

primary key (id)

)

create tablePerson (

id integernot null,

namevarchar(255),

primary key(id)

)

alter table person

add index FK785BED805248EF3 (id),

add constraint FK785BED805248EF3

foreign key (id) references idcard (id)

注意:annotation注解后,并没有映射出外键关键的关联,而xml可以映射,是主键关联不重要

8、 存储测试

session = HibernateUtils.getSession();

tx = session.beginTransaction();

IdCard idCard = new IdCard();

idCard.setCardNo("88888888888888888888888");

Person person = new Person();

person.setName("菜10");

person.setIdCard(idCard);

//不会出现TransientObjectException异常

//因为一对一主键关键映射中,默认了cascade属性。

session.save(person);

tx.commit();

9、 总结

让两个实体对象的ID保持相同,这样可以避免多余的字段被创建

<id name="id"column="id">

<!—person的主键来源idcard,也就是共享idCard的主键-->

<generator class="foreign">

<param name="property">idCard</param>

</generator>

</id>

<property name="name"/>

<!—one-to-one标签的含义:指示hibernate怎么加载它的关联对象,默认根据主键加载

constrained="true",表面当前主键上存在一个约束:person的主键作为外键参照了idCard-->

<one-to-one name="idCard" constrained="true"/>

(四) 主键关联-双向(不重要)

主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联。

主键关联映射,实际是数据库的存储结构并没有变化,只是要求双方都可以持有对象引用,也就是说实体模型变化,实体类都相互持有对方引用。

另外映射文件也变化了。

1、 xml映射

Person实体类映射文件不变,

IdCard如下:

<class name="com.wjt276.hibernate.IdCard" table="t_idcard">

<id name="id" column="id">

<generator class="native"/> </id>

<property name="cardNo"/>

<!—one-to-one标签的含义:指示hibernate怎么加载它的关联对象(这里的关联对象为person),默认根据主键加载-->

<one-to-one name="person"/>

</class>

2、 annotateon注解映射:

Person的注解不变,同主键单向注解

 

IdCard注解,只需要在持有对象引用的getXXX前加上

        @OneToOne(mappedBy="idCard") 如下:

@Entity

public class IdCard {

private int id;

private String cardNo;

private Person person;

@OneToOne(mappedBy="idCard")

public Person getPerson(){

return person;

}}

(五) 联合主键关联(Annotation方式)

实现上联合主键的原理同唯一外键关联-单向一样,只是使用的是@JoinColumns,而不是@JoinColumn,实体类注解如下:

@OneToOne

@JoinColumns(

{

@JoinColumn(name="wifeId", referencedColumnName="id"),

@JoinColumn(name="wifeName", referencedColumnName="name")

}

)

public WifegetWife() {

return wife;

}

注意:@oinColumns注解联合主键一对一联系,然后再使用@JoinColumn来注解当前表中的外键字段名,并指定关联哪个字段,使用referencedColumnName指定哪个字段的名称

二、 component(组件)关联映射

(一) Component关联映射:

目前有两个类如下:

大家发现用户与员工存在很多相同的字段,但是两者有不可以是同一个类中,这样在实体类中每次都要输入很多信息,现在把联系信息抽取出来成为一个类,然后在用户、员工对象中引用就可以,如下:

值对象没有标识,而实体对象具有标识,值对象属于某一个实体,使用它重复使用率提升,而且更清析。

以上关系的映射称为component(组件)关联映射

在hibernate中,component是某个实体的逻辑组成部分,它与实体的根本区别是没有oid,component可以成为是值对象(DDD)。

采用component映射的好处:它实现了对象模型的细粒度划分,层次会更加分明,复用率会更高。

(二) User实体类:

public class User {

private int id;

private String name;

private Contact contact;//值对象的引用

public int getId() {return id;}

public void setId(int id) { this.id = id;}

public String getName() {   return name;}

public void setName(Stringname) {  this.name = name;}

public ContactgetContact() {   return contact;}

public void setContact(Contactcontact) {   this.contact = contact;}

}

(三) Contact值对象:

public class Contact {

private String email;

private String address;

private String zipCode;

private String contactTel;

public String getEmail(){  return email;}

public void setEmail(Stringemail) {    this.email = email; }

public StringgetAddress() {return address;}

public void setAddress(Stringaddress) {this.address = address;}

public StringgetZipCode() {return zipCode;}

public void setZipCode(StringzipCode) {this.zipCode = zipCode;}

public StringgetContactTel() { return contactTel;}

public voidsetContactTel(String contactTel){this.contactTel = contactTel;}

}

(四) xml--User映射文件(组件映射):

<hibernate-mapping>

<class name="com.wjt276.hibernate.User" table="t_user">

<id name="id" column="id">

<generator class="native"/>

</id>

<property name="name" column="name"/>

<!-- <component>标签用于映射Component(组件)关系

其内部属性正常映射。

-->

<component name="contact">

<property name="email"/>

<property name="address"/>

<property name="zipCode"/>

<property name="contactTel"/>

</component>

</class>

</hibernate-mapping>

(五) annotateon注解

使用@Embedded用于注解组件映射,表示嵌入对象的映射

@Entity

public class User {

private int id;

private String name;

private Contact contact;//值对象的引用

@Id

@GeneratedValue

public int getId() {    return id;}

@Embedded//用于注解组件映射,表示嵌入对象的映射

public ContactgetContact() {return contact;}

public void setContact(Contactcontact) {this.contact = contact;}

Contact类是值对象,不是实体对象,是属于实体类的某一部分,因此没有映射文件

(六) 导出数据库输出SQL语句:

create table User (

id integer not null auto_increment,

address varchar(255),

contactTel varchar(255),

email varchar(255),

zipCode varchar(255),

name varchar(255),

primary key (id)

)

(七) 数据表结构:

注:虽然实体类没有基本联系信息,只是有一个引用,但在映射数据库时全部都映射进来了。以后值对象可以重复使用,只要在相应的实体类中加入一个引用即可。

(八) 组件映射数据保存:

session =HibernateUtils.getSession();

tx =session.beginTransaction();

User user= new User();

user.setName("10");

Contactcontact = new Contact();

contact.setEmail("wjt276");

contact.setAddress("aksdfj");

contact.setZipCode("230051");

contact.setContactTel("3464661");

user.setContact(contact);

session.save(user);

tx.commit();

实体类中引用值对象时,不用先保存值对象,因为它不是实体类,它只是一个附属类,而session.save()中保存的对象是实体类。

Hibernate学习笔记(四)关系映射之一对一关联映射的更多相关文章

  1. java之hibernate之基于主键的双向一对一关联映射

    这篇 基于主键的双向一对一关联映射 1.依然考察人和身份证的一对一关系,如果采用主键关联,那么其表结构为: 2.类结构 Person.java public class Person implemen ...

  2. java之hibernate之基于主键的单向一对一关联映射

    这篇讲 基于主键的单向一对一关联映射 1.依然考察人和身份证的一对一关系,如果采用主键关联,那么其表结构应该为: 2.类结构 Person.java public class Person imple ...

  3. java之hibernate之基于外键的双向一对一关联映射

    这篇讲解 基于外键的双向一对一关联映射 1.考察如下信息,人和身份证之间是一个一对一的关系.表的设计 2.类结构 Person.java public class Person implements ...

  4. 【Hibernate框架】关联映射(一对一关联映射)

    一.整理思路: 之前,小编总结过Mybatis的关联映射,接下来,再来总结一下hibernate的相关的关联映射,直接上图: 这张图,就是小编整理总结整个Hibernate的关联映射的一个大致思路. ...

  5. Hibernate学习笔记四

    1 整合log4j(了解) l slf4j 核心jar  : slf4j-api-1.6.1.jar .slf4j是日志框架,将其他优秀的日志第三方进行整合. l 整合导入jar包 log4j 核心包 ...

  6. Hibernate学习笔记四 查询

    HQL语法 1.基本语法 String hql = " from com.yyb.domain.Customer ";//完整写法 String hql2 = " fro ...

  7. Hibernate学习笔记四:事务管理

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6768298.html  一:需要事务的Session操作 Session操作中,查询类操作是不需要事务就能生效 ...

  8. 【学习笔记】Hibernate 一对一关联映射 组件映射 二级缓存 集合缓存

    啊讲道理放假这十天不到啊 感觉生活中充满了绝望 这就又开学了 好吧好吧继续学习笔记?还是什么的 一对一关联映射 这次我们仍然准备了两个表 一个是用户表Users 一个是档案表Resume 他们的关系是 ...

  9. HIbernate学习笔记(六) 关系映射之多对多

    六.多对多 - 单向 Ø        一般的设计中,多对多关联映射,需要一个中间表 Ø        Hibernate会自动生成中间表 Ø        Hibernate使用many-to-ma ...

随机推荐

  1. 团体程序设计天梯赛-练习集L1-005. 考试座位号

    L1-005. 考试座位号 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 每个PAT考生在参加考试时都会被分配两个座位号,一个 ...

  2. Hex string convert to integer with stringstream

    #include <sstream>#include <iostream>int main() { unsigned int x; std::stringstream ss; ...

  3. 使用JS动态创建含有1000行的表格

    function addTable(){ createTable1(1000); //createTable2(1000); //createTable3(1000); //createTable4( ...

  4. Android Spinner(级联 天气预报)

    activity_spinner.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayo ...

  5. Qt之自定义控件(开关按钮)Qt之模拟时钟

    http://blog.csdn.net/u011012932/article/details/52164289 http://blog.csdn.net/u011012932/article/det ...

  6. font-size:100%和font-size:0

    h1,h2,h3,h4,h5,h6 {font-size:100%;} 正常情况下hx按照一定百分比增加字号,但是指定font-size:100%;就会继承body设置的字体大小 font-size: ...

  7. nginx + tomcat

    http://blog.csdn.net/sun305355024sun/article/details/8620996

  8. hdu2642Fliping game

    http://acm.hdu.edu.cn/showproblem.php?pid=4642 这题..刚一看以为是什么高深的博弈 后来看过的人挺多 想是不是有什么规律 结果理解错题意了 以为随便圈一矩 ...

  9. poj 2299 Ultra-QuickSort (归并排序 求逆序数)

    题目:http://poj.org/problem?id=2299 这个题目实际就是求逆序数,注意 long long 上白书上的模板 #include <iostream> #inclu ...

  10. createSQLQuery与createQuery的区别

    本文原址 : http://stta04.javaeye.com/blog/377633hibernate 中createQuery与createSQLQuery 昨晚帮同事看代码到凌晨2点多,今早6 ...