Hibernate关联映射之多对一、一对一映射

来源:互联网 发布:suse linux yum配置 编辑:程序博客网 时间:2024/06/05 22:39

多对一关联映射

     原理是在多的一端加入外键指向一的一端。采用<many-to-one>标签。cascade(级联)属性,作用是两个对象连锁操作,取值有none(默认)、all、sava-update(推荐)、delete。
    示例:
    User实体
public class User {private int id;private String name;private String password;private Date birthday;private Group group;public User() {}public User(String name, String password, Date birthday) {this.name = name;this.password = password;this.birthday = birthday;}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 String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public Group getGroup() {return group;}public void setGroup(Group group) {this.group = group;}
    User.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.User" table="t_user"><id name="id" column="userID"><generator class="native" /><!-- 主键 --><!-- native/uuid --></id><property name="name" type="string" length="30" unique="true"not-null="true" /><property name="password" /><property name="birthday" type="date" /><many-to-one name="group" column="groupId" cascade="save-update"></many-to-one></class></hibernate-mapping>
    Group实体:
public class Group {private String id;private String name;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}
    Group.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Group" table="t_group"><id name="id" column="id"><generator class="native" /><!-- 主键 --></id><property name="name" type="string" length="30" unique="true"not-null="true" /></class></hibernate-mapping>
    生成的建表指令:(<many-to-one>会加字段)
    drop table if exists t_group    drop table if exists t_user    create table t_group (        id varchar(255) not null auto_increment,        name varchar(30) not null,        primary key (id))    create table t_user (        userID integer not null auto_increment,        name varchar(30) not null,        password varchar(255),        birthday date,        groupId varchar(255),        primary key (userID)    )    alter table t_group         add constraint UK_sw96rg1m1r6q8cp787dx7ugru  unique (name)    alter table t_user         add constraint UK_g8gqk4e142wekcb1t6d3v2mwx  unique (name)    alter table t_user         add constraint FK_7ktm6l2qkykpqrf6oq01ys8wy         foreign key (groupId)         references t_group (id)
    测试:
//在没设置cascade="save-update"情况下Group group = new Group();group.setName("AAAAAAAA");User u1 = new User("aaa","123",new Date());u1.setGroup(group);User u2 = new User("aaa","123",new Date());u2.setGroup(group);session.save(u1);session.save(u2);//在清理缓存是发生错误TransientObjectException.//因为Group为Transient状态,没有被session,在数据库中没有匹配的数据//而User为Persistent状态,在清理缓存时hibernate在缓存中无法找到Group对象

//在没设置cascade="save-update"情况下Group group = new Group();group.setName("AAAAAAAA");session.save(group);User u1 = new User("aaa","123",new Date());u1.setGroup(group);User u2 = new User("aaa","123",new Date());u2.setGroup(group);session.save(u1);session.save(u2);//可以正确的保存数据//因为Group和User都是Persistent状态的对象//所以在hibernate清理缓存时在session中可以找到关联对象

//在设置cascade="save-update"情况下Group group = new Group();group.setName("AAAAAAAA");User u1 = new User("aaa","123",new Date());u1.setGroup(group);User u2 = new User("aaa","123",new Date());u2.setGroup(group);session.save(u1);session.save(u2);session.save(user1);session.save(user2);//没有抛出TransientObjectException异常//因为使用了级联特性//hibernate会首先保存User的关联对象对象Group//Group和User就都是Persistent状态的对象了


一对一关联映射

方式一. 让两个实体的主键一样,无需要加入多余的字段

1.单向关联Person----->IDCard
    Person实体:
public class Person {private int id;private String name;private 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(IDCard iDCard) {IDCard = iDCard;}}
    Person.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Person" table="t_person"><id name="id"><!-- 采用foreign生成策略,foreign会取得关联对象的标识 --><generator class="foreign"><!-- property 指关联对象 --><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" /></class></hibernate-mapping>
    IDCard实体:
public class IDCard {private int id;private String cardNum;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getCardNum() {return cardNum;}public void setCardNum(String cardNum) {this.cardNum = cardNum;}}
    IDCard.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.IDCard" table="t_IDCard"><id name="id"><generator class="native"/></id><property name="cardNum"/></class></hibernate-mapping>
    生成的建表指令:(<one-to-one>不会加字段)
    alter table t_person         drop         foreign key FK_q2gx6s9cco0dl5pd4b0xexsad    drop table if exists t_IDCard    drop table if exists t_person    create table t_IDCard (        id integer not null auto_increment,        cardNum varchar(255),        primary key (id)    )    create table t_person (        id integer not null,        name varchar(255),        primary key (id)    )    alter table t_person         add constraint FK_q2gx6s9cco0dl5pd4b0xexsad         foreign key (id)         references t_IDCard (id)
    测试:
IDCard idCard = new IDCard();idCard.setCardNum("123456789");Person person = new Person();person.setName("萧");// 建立关联person.setIDCard(idCard);// 没有抛出TransientObjectException// 是由一对一关联映射的特性决定的,它必须先保存关联对象IdCard// 这样它采用foreign映射策略才能取得关联对象的标识// 也就是它默认了cascade属性session.save(person);

IDCard idCard = new IDCard();idCard.setCardNum("12234567");Person person = new Person();person.setName("zero");// 建立关联person.setIDCard(idCard);// 只能将IdCard保存,不能将Person保存// 因为关系的维护端在Person端,IDCard不知道Person的存在session.save(idCard);

2. 双向关联Person<----->IDCard. 
    需要在IDCard加入<one-to-one>标签,指示hibernate将关联对象Person根据主键加载上来. 这里的<one-to-one>不影响存储,只影响加载。
    Person实体:
public class Person {private int id;private String name;private 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(IDCard iDCard) {IDCard = iDCard;}}
    Person.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Person" table="t_person"><id name="id"><!-- 采用foreign生成策略,foreign会取得关联对象的标识 --><generator class="foreign"><!-- property 指关联对象 --><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" /></class></hibernate-mapping>
    IDCard实体:
public class IDCard {private int id;private String cardNum;private Person person;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getCardNum() {return cardNum;}public void setCardNum(String cardNum) {this.cardNum = cardNum;}public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;}}
    IDCard.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.IDCard" table="t_IDCard"><id name="id"><generator class="native" /></id><property name="cardNum" /><one-to-one name="person" /></class></hibernate-mapping>
    生成的建表指令:
    alter table t_person         drop         foreign key FK_q2gx6s9cco0dl5pd4b0xexsad    drop table if exists t_IDCard    drop table if exists t_person    create table t_IDCard (        id integer not null auto_increment,        cardNum varchar(255),        primary key (id)    )    create table t_person (        id integer not null,        name varchar(255),        primary key (id)    )    alter table t_person         add constraint FK_q2gx6s9cco0dl5pd4b0xexsad         foreign key (id)         references t_IDCard (id)
    测试:
IDCard idCard = new IDCard();idCard.setCardNum("12234567");Person person = new Person();person.setName("zero");// 建立关联person.setIDCard(idCard);// 只能将IdCard保存,不能将Person保存// 因为关系的维护端还是在Person端session.save(idCard);


方式二. 唯一外键关联映射

1.单向关联Person----->IDCard
    一对一唯一外键关联映射其实是多对一的特例,采用<many-to-one>标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性为一,就是这样来映射的。
    Person实体:
public class Person {private int id;private String name;private 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(IDCard iDCard) {IDCard = iDCard;}}
    Person.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Person" table="t_person"><id name="id"><generator class="native" /></id><property name="name" /><many-to-one name="IDCard" unique="true" /></class></hibernate-mapping>
    IDCard实体:
public class IDCard {private int id;private String cardNum;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getCardNum() {return cardNum;}public void setCardNum(String cardNum) {this.cardNum = cardNum;}}
    IDCard.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.IDCard" table="t_IDCard"><id name="id"><generator class="native" /></id><property name="cardNum" /></class></hibernate-mapping>
    生成的建表指令:
    alter table t_person         drop         foreign key FK_84cux32o4j1hukfr5khsx0cjedrop table if exists t_IDCarddrop table if exists t_person    create table t_IDCard (        id integer not null auto_increment,        cardNum varchar(255),        primary key (id)    )    create table t_person (        id integer not null auto_increment,        name varchar(255),        IDCard integer,        primary key (id))    alter table t_person         add constraint UK_84cux32o4j1hukfr5khsx0cje  unique (IDCard)    alter table t_person         add constraint FK_84cux32o4j1hukfr5khsx0cje         foreign key (IDCard)         references t_IDCard (id)
    测试:
IDCard idCard = new IDCard();idCard.setCardNum("123456789");Person person = new Person();person.setName("萧");// 建立关联person.setIDCard(idCard);//抛出TransientObjectException//因为IdCard为Transient状态session.save(person);

IDCard idCard = new IDCard();idCard.setCardNum("123456789");session.save(idCard);Person person = new Person();person.setName("萧");// 建立关联person.setIDCard(idCard);session.save(person);//保存成功

2. 双向关联Person<----->IDCard. 
    一对一唯一外键双向关联在IDCard端采用<one-to-one>标签映射,必须指定<one-to-one>标签中的property-ref属性为关系字段的名称。
    Person实体:
public class Person {private int id;private String name;private 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(IDCard iDCard) {IDCard = iDCard;}}
    Person.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.Person" table="t_person"><id name="id"><generator class="native" /></id><property name="name" /><many-to-one name="IDCard" unique="true" /></class></hibernate-mapping>
    IDCard实体:
public class IDCard {private int id;private String cardNum;private Person person;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getCardNum() {return cardNum;}public void setCardNum(String cardNum) {this.cardNum = cardNum;}public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;}}
    IDCard.hbm.xml
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.zero.hibernate.vo.IDCard" table="t_IDCard"><id name="id"><generator class="native" /></id><property name="cardNum" /><one-to-one name="person" property-ref="IDCard"/></class></hibernate-mapping>
    生成的建表指令:
    alter table t_person         drop         foreign key FK_84cux32o4j1hukfr5khsx0cje    drop table if exists t_IDCard    drop table if exists t_person    create table t_IDCard (        id integer not null auto_increment,        cardNum varchar(255),        primary key (id)    )    create table t_person (        id integer not null auto_increment,        name varchar(255),        IDCard integer,        primary key (id)    )    alter table t_person         add constraint UK_84cux32o4j1hukfr5khsx0cje  unique (IDCard)    alter table t_person         add constraint FK_84cux32o4j1hukfr5khsx0cje         foreign key (IDCard)         references t_IDCard (id)
    测试:
Person person = (Person)session.load(Person.class, 1);System.out.println("person.name=" + person.getName());System.out.println("person.cardNo=" + person.getIDCard().getCardNum());IDCard idCard = (IDCard)session.load(IDCard.class, 1);System.out.println("idCard.cardNum = " + idCard.getCardNum());System.out.println("idCard.person.name = " + idCard.getPerson().getName());//均可以查询出结果

0 0