一对一关联映射

Posted Super-song

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一对一关联映射相关的知识,希望对你有一定的参考价值。

Hibernate中实现一对一映射有基于外键的方式和基于主键的方式。由于基于主键方式的映射在实现删除等操作时存在的问题且不够灵活,一般建议使用基于外键的方式实现。

技术分享

以个人与身份证的关系为例(主要看映射文件的配置和实体类):

基于外键的方式(只有有外键方可以维护关联关系):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package test.hibernate.hbmOneToOne;
 
public class Person {
 
    private Integer id;
    private String name;
    private IDCard idCard;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer 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) {
        this.idCard = idCard;
    }
 
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "[Person:id=" + id + ",name=" + name + "]";
    }
 
}



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package test.hibernate.hbmOneToOne;
 
public class IDCard {
 
    private Integer id;
    private String IDNumber;
    private Person person;
 
    public Integer getId() {
        return id;
    }
 
    public void setId(Integer id) {
        this.id = id;
    }
 
    public String getIDNumber() {
        return IDNumber;
    }
 
    public void setIDNumber(String iDNumber) {
        IDNumber = iDNumber;
    }
 
    public Person getPerson() {
        return person;
    }
 
    public void setPerson(Person person) {
        this.person = person;
    }
    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "[IDCard:id="+id+",IDNumber="+IDNumber+"]";
    }
 
}



Person.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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 package="test.hibernate.hbmOneToOne">
    <class name="Person" table="person">
        <id name="id" type="integer" column="id">
            <generator class="native" />
        </id>
        <property name="name" />
        <one-to-one name="idCard" class="IDCard" property-ref="person"></one-to-one>
    </class>
</hibernate-mapping>

IDCard.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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 package="test.hibernate.hbmOneToOne">
    <class name="IDCard" table="idCard">
        <id name="id" type="integer" column="id">
            <generator class="native" />
        </id>
        <property name="IDNumber" />
        <many-to-one name="person" class="Person" column="personId" unique="true">
        </many-to-one>
 
    </class>
</hibernate-mapping>



测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package test.hibernate.hbmOneToOne;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
 
public class App {
 
    private static SessionFactory sessionFactory = new Configuration()//
            .configure()//
            .addClass(Person.class)// 添加Hibernate实体类(加载对应的映射文件)
            .addClass(IDCard.class)//
            .buildSessionFactory();
 
    @Test
    public void testSave() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------
 
        // 构建对象
        Person person = new Person();
        person.setName("张三");
 
        IDCard idCard = new IDCard();
        idCard.setIDNumber("377489392002121X");
 
        // 关联起来
        person.setIdCard(idCard);
        idCard.setPerson(person);
 
        // 保存
        session.save(person);
        session.save(idCard);
 
        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }
 
    @Test
    public void testGet() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
 
        // 获取数据
        Person person = (Person) session.get(Person.class, 2);
        System.out.println(person);
        System.out.println(person.getIdCard());
 
        IDCard idCard = (IDCard) session.get(IDCard.class, 2);
        System.out.println(idCard);
        System.out.println(idCard.getPerson());
 
        session.getTransaction().commit();
        session.close();
    }
 
    // 解除关联关系,从有外键方
    @Test
    public void testRemoveRelation() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------
 
        IDCard idCard = (IDCard) session.get(IDCard.class, 1);
        idCard.setPerson(null);
 
        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }
 
    // 删除,只能做有外键方到无外键方的单向关联
    @Test
    public void testDelete() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------
 
        // Person person=(Person) session.get(Person.class, 2);
        // session.delete(person);//删除失败,有personId外键,抛出异常
 
        IDCard idCard = (IDCard) session.get(IDCard.class, 3);
        session.delete(idCard);// 卡删了,人还在
 
        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }
}



基于主键的方式(双方都不可以维护关联关系,映射文件配置有所不同):

Person.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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 package="test.hibernate.hbmOneToOne2">
    <class name="Person" table="person2">
        <id name="id" type="integer" column="id">
            <generator class="native" />
        </id>
        <property name="name" />
        <one-to-one name="idCard" class="IDCard"></one-to-one>
    </class>
</hibernate-mapping>

IDCard.hbm.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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 package="test.hibernate.hbmOneToOne2">
    <class name="IDCard" table="idCard2">
        <id name="id" type="integer" column="id">
            <!--
            当使用基于主键的一对一映射时,有外键方的主键
            生成策略 一定要是foreign。
            参数property:生成主键值时所根据的对象。
             -->
            <generator class="foreign">
                <param name="property">person</param>
            </generator>
        </id>
        <property name="IDNumber" />
        <!-- constrained外键约束 -->
        <one-to-one name="person" class="Person" constrained="true">
        </one-to-one>
 
    </class>
</hibernate-mapping>



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package test.hibernate.hbmOneToOne2;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
 
public class App {
 
    private static SessionFactory sessionFactory = new Configuration()//
            .configure()//
            .addClass(Person.class)// 添加Hibernate实体类(加载对应的映射文件)
            .addClass(IDCard.class)//
            .buildSessionFactory();
 
    @Test
    public void testSave() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------
 
        // 构建对象
        Person person = new Person();
        person.setName("张三");
 
        IDCard idCard = new IDCard();
        idCard.setIDNumber("377489392002121X");
 
        // 关联起来
        person.setIdCard(idCard);
        idCard.setPerson(person);
 
        // 保存
//      session.save(person);
        session.save(idCard);
 
        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }
 
    // 解除关联关系
    @Test
    public void testRemoveRelation() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------
 
//      IDCard idCard = (IDCard) session.get(IDCard.class, 1);
//      idCard.setPerson(null);//抛异常
         
        Person person=(Person) session.get(Person.class, 3);
        person.setIdCard(null);//数据库中的数据没有改变
 
        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }
 
    // 删除
    @Test
    public void testDelete() throws Exception {
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        // --------------------------------------------
 
//      IDCard idCard = (IDCard) session.get(IDCard.class, 2);
//      session.delete(idCard);//正常
         
        Person person=(Person) session.get(Person.class, 3);
        session.delete(person);//抛异常,id作为外键
 
        // --------------------------------------------
        session.getTransaction().commit();
        session.close();
    }
}

以上是关于一对一关联映射的主要内容,如果未能解决你的问题,请参考以下文章

mybatis第二天——大纲待更新

hibernate关联映射一对一主键

Hibernate 映射一对一关联关系

Hibernate—— 联合主键 一对一关联关系映射(xml和注解) 和 领域驱动设计

hibernate关联映射

关联映射级联操作关系维护 ---- Hibernate之一对多|多对一关系