在现实生活中,一对一的映射关系不是很多,相对于多对多,一对多比较简单,比如:学生和学生信息就是一个一对一的关系。
在hibernate中有两种方式可以实现一对一的映射关系:
1.主键关联:即让两个对象拥有相同的主键值,以表明他们之间的一一对应关系,数据库表不会有额外的字段来维护他们之间的关系,仅通过表的主键来关联。
2.唯一外键关联:外键关联原本是用于一对多的映射,但是如果加上唯一的限制之后,也可以用来表示一对一关联关系。
主键关联实现一对一
先来看下Student和StudentInfo这两个类:
StudentInfo.java
package x.y.z;
public class StudentInfo {
private int infoId;
private String realName;
private String qq;
//基本信息
private Student base;
public int getInfoId() {
return infoId;
}
public void setInfoId(int infoId) {
this.infoId = infoId;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
public Student getBase() {
return base;
}
public void setBase(Student base) {
this.base = base;
}
public StudentInfo(){}
public StudentInfo(int infoId,String realName,String qq){
this.infoId = infoId;
this.realName = realName;
this.qq = qq;
}
}
Student.java
package x.y.z;
public class Student {
private int stuid;
private String stuname;
//详细信息
private StudentInfo info;
public Student(){}
public Student(int stuid,String stuname){
this.stuid = stuid;
this.stuname = stuname;
}
public int getStuid() {
return stuid;
}
public void setStuid(int stuid) {
this.stuid = stuid;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public StudentInfo getInfo() {
return info;
}
public void setInfo(StudentInfo info) {
this.info = info;
}
}
可以看到在Student和StudentInfo这两个类当中,都有对方的引用。
StudentInfo.hbm.xml
<hibernate-mapping>
<class name="x.y.z.StudentInfo">
<id name="infoId">
<generator class="foreign">
<param name="property">base</param><!-- 把Student的主键 当做StudentInfo的外键 -->
</generator>
</id>
<property name="realName"></property>
<property name="qq"></property>
<one-to-one name="base" constrained="true" />
</class>
</hibernate-mapping>
Student.hbm.xml
<hibernate-mapping>
<class name="x.y.z.Student">
<id name="stuid">
<generator class="native"/>
</id>
<property name="stuname"></property>
<one-to-one name="info"/> <!-- Student.java实体类的第八行info -->
</class>
</hibernate-mapping>
根据映射文件可以看出:studentInfo的主键依赖于student的主键,这就保证了一对一的映射。
下面实现一对一的插入操作:
Session session = new Configuration().configure().buildSessionFactory().openSession();
session.beginTransaction();
Student s1 = new Student(0,"张三");
Student s2 = new Student(0,"李四");
StudentInfo info1 = new StudentInfo(100,"张大三","1234567");
StudentInfo info2 = new StudentInfo(200,"李小四","7654321");
//由约束方StudentInfo维护关系
info1.setBase(s1);
info2.setBase(s2);
session.save(s1);
session.save(s2);
session.save(info1);
session.save(info2);
session.getTransaction().commit();
session.close();
唯一外键关联实现一对一映射
可以通过一对多实现特殊的一对一,当多方只有一个的时候,就是标准的一对一实现。
Student.hbm.xml
<hibernate-mapping>
<class name="x.y.z.Student">
<id name="stuid">
<generator class="native"/>
</id>
<property name="stuname"></property>
<one-to-one name="info"/>
</class>
</hibernate-mapping>
StudentInfo.hbm.xml
<hibernate-mapping>
<class name="x.y.z.StudentInfo">
<id name="infoId">
<generator class="assigned"/>
</id>
<property name="realName"></property>
<property name="qq"></property>
<many-to-one name="base" unique="true" column="s_id"/> <!-- 有约束方维护关系 -->
<!-- 特殊的many-to-one,一对一(把以前的多个合并成一个) -->
</class>
</hibernate-mapping>
hibernate多对多实现
在hibernate中多对多的实现都是通过一个中间表来将其转换成两个一对多的。这里我以Market和Product来做例子,比如:一个超市可以出售多种商品,一个商品也可以在多个超市里边出售。先来看下这两个实体类:
Market.java
public class Maket {
private int mid;
private String mname;
private String maddr;
Set<Product> prods = new HashSet<Product>();
public Maket() {
super();
}
public Maket(int mid, String mname, String maddr) {
super();
this.mid = mid;
this.mname = mname;
this.maddr = maddr;
}
public int getMid() {
return mid;
}
public void setMid(int mid) {
this.mid = mid;
}
public String getMname() {
return mname;
}
public void setMname(String mname) {
this.mname = mname;
}
public String getMaddr() {
return maddr;
}
public void setMaddr(String maddr) {
this.maddr = maddr;
}
public Set<Product> getProds() {
return prods;
}
public void setProds(Set<Product> prods) {
this.prods = prods;
}
}
Product.java
public class Product {
private int pid;
private String pname;
private double price;
Set<Maket> tomakets = new HashSet<Maket>();
public Product() {
super();
}
public Product(int pid, String pname, double price) {
super();
this.pid = pid;
this.pname = pname;
this.price = price;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Set<Maket> getTomakets() {
return tomakets;
}
public void setTomakets(Set<Maket> tomakets) {
this.tomakets = tomakets;
}
}
可以看到在Market和Product中都有各自引用。
product.hbm.xml
<hibernate-mapping>
<class name="a.b.c.Product">
<id name="pid">
<generator class="native"/>
</id>
<property name="pname"/>
<property name="price"/>
<set name="tomakets" table="prod_mkt" inverse="true" cascade="all">
<key column="p_id"/>
<many-to-many class="a.b.c.Maket" column="m_id"/>
</set>
</class>
</hibernate-mapping>
说明一下:”prod_mkt”是生成的中间表的名称,inverse=”true”表示有对方来维护关系,”p_id”表示该类所对应的生成的中间表的外键。。
Maket.hbm.xml
<hibernate-mapping>
<class name="a.b.c.Maket">
<id name="mid">
<generator class="native"/>
</id>
<property name="mname"/>
<property name="maddr"/>
<set name="prods" table="prod_mkt" cascade="all">
<key column="m_id"/>
<many-to-many class="a.b.c.Product" column="p_id"/>
</set>
</class>
</hibernate-mapping>
好了,关于hibernate的映射的配置就学习到这里了。