Hibernate关联关系映射

2 篇文章 0 订阅
1 篇文章 0 订阅

刚使用Hibernate的时候经常被各种关系关联映射弄得头大, 在这里来总结一些单向关联映射和双向关联映射案例.

单向关联( Unidirectional associations )

多对一( many-to-one )

单向many-to-one关联是最常见的单项关联关系, 这里使用Customer和Order为例, Customer为一的一方, Order为多的一方
Order配置 :

<class name="Order" table="u_order" catalog="hibernateTest_1">
    <id name="id" column="o_id" >
        <generator class="native"></generator>
    </id>
    <property name="price" column="o_price"></property>
    <property name="address" column="address"></property>
        <many-to-one name="customer" class="Customer" column="c_id" cascade="save-update"/>
</class>

Customer配置:

<class name="Customer" table="u_customer" catalog="hibernateTest_1">
    <id name="id" column="c_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
</class>

测试代码:这里要注意的是我在Order中配置了cascade="save-update" ,因此在代码中Order单向关联Customer, 通过只保存Order来保存完整数据. 之后的代码也会采用同样的方法, 就不再赘述了

Order o1 = new Order();
o1.setPrice(1888d);
o1.setAddress("Beijing");
Order o2 = new Order();
o2.setPrice(2888d);
o2.setAddress("NewYork");
Customer c = new Customer();
c.setName("Tom");

o1.setCustomer(c);
o2.setCustomer(c);

session.save(o1);
session.save(o2);

一对多( one-to-many )

同样使用Customer和Order为例, 这里用Customer关联Order. 但是基于外键关联的单向一对多关联是一种很少见的情况,我们不推荐使用它.
Customer配置:

<class name="Customer" table="u_customer" catalog="hibernateTest_1">
    <id name="id" column="c_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
    <set name="orders" cascade="save-update">
        <key column="c_id"/>
        <one-to-many class="Order"/>
    </set>
</class>

Order配置:

<class name="Order" table="u_order" catalog="hibernateTest_1">
    <id name="id" column="o_id" >
        <generator class="native"></generator>
    </id>
    <property name="price" column="o_price"></property>
    <property name="address" column="address"></property>
</class>

测试代码 :

Order o1 = new Order();
o1.setPrice(1888d);
o1.setAddress("Beijing");
Order o2 = new Order();
o2.setPrice(2888d);
o2.setAddress("NewYork");
Customer c = new Customer();
c.setName("Tom");

c.getOrders().add(o1);
c.getOrders().add(o2);

session.save(c);

一对一( one-to-one )

一对一关联有两种情况, 基于外键和基于主键:

基于外键的一对一关联

基于外键关联的单向一对一关联和单向多对一关联几乎是一样的. 唯一的不同就是单向一对一关联中的外键字段具有唯一性约束. 这里使用Person和IDcard, 用Person来关联IDcard:
Person配置:

<class name="Person" table="u_person" catalog="hibernateTest_1">
    <id name="id" column="p_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="p_name"></property>
    <many-to-one name="idcard" class="IDcard" column="i_id" cascade="save-update"/>
</class>

IDcard配置:

<class name="IDcard" table="u_idcard" catalog="hibernateTest_1">
    <id name="id" column="i_id">
        <generator class="native"></generator>
    </id>
    <property name="idnum" column="i_idnum"></property>
</class>

测试代码:

Person p = new Person();
p.setName("jack");
IDcard i = new IDcard();
i.setIdnum("500201199111112345");
p.setIdcard(i);

session.save(p);

基于主键的一对一关联

这里我使用Husband-Wife来说明

Wife配置:

<class name="Wife" table="u_wife" catalog="hibernateTest_1">
    <id name="id" column="w_id" >
        <generator class="foreign">
            <param name="property">husband</param>
        </generator>
    </id>
    <property name="name" column="w_name"></property>
    <one-to-one name="husband" cascade="save-update"/>
</class>

Husband配置:

<class name="Husband" table="u_husband" catalog="hibernateTest_1">
    <id name="id" column="h_id" >
        <generator class="native"></generator>
    </id>
    <property name="name" column="h_name"></property>
</class>

测试代码:

Husband h = new Husband();
h.setName("LiLei");
Wife w = new Wife();
w.setName("HanMeimei");

w.setHusband(h);

session.save(w);

使用连接表的单向关联(Unidirectional associations with join tables)

多对一(many-to-one)

Order配置

<class name="Order" table="u_order" catalog="hibernateTest_1">
    <id name="id" column="o_id" >
        <generator class="native"></generator>
    </id>
    <property name="price" column="o_price"></property>
    <property name="address" column="address"></property>
    <join table="customer_order">
        <key column="o_id"/>
        <many-to-one name="customer" class="Customer" column="c_id" cascade="save-update"/>
    </join>
</class>

Customer配置

<class name="Customer" table="u_customer" catalog="hibernateTest_1">
    <id name="id" column="c_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
</class>

测试代码:

Order o1 = new Order();
o1.setPrice(1888d);
o1.setAddress("Beijing");
Order o2 = new Order();
o2.setPrice(2888d);
o2.setAddress("NewYork");
Customer c = new Customer();
c.setName("Tom");

o1.setCustomer(c);
o2.setCustomer(c);

session.save(o1);
session.save(o2);

一对多 ( one-to-many )

我们应该优先采用基于连接表的单向一对多关联. 通过指定 unique="true",我们可以把多对多关联关系变为一对多关联关系
Customer配置:

<class name="Customer" table="u_customer" catalog="hibernateTest_1">
    <id name="id" column="c_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
    <set name="orders" cascade="save-update" table="customer_order">
        <key column="c_id"/>
        <many-to-many class="Order" column="o_id"/>
    </set>
</class>

Order配置:

<class name="Order" table="u_order" catalog="hibernateTest_1">
    <id name="id" column="o_id" >
        <generator class="native"></generator>
    </id>
    <property name="price" column="o_price"></property>
    <property name="address" column="address"></property>
</class>

测试代码:

Order o1 = new Order();
o1.setPrice(1888d);
o1.setAddress("Beijing");
Order o2 = new Order();
o2.setPrice(2888d);
o2.setAddress("NewYork");
Customer c = new Customer();
c.setName("Tom");

c.getOrders().add(o1);
c.getOrders().add(o2);

session.save(c);

一对一( one-to-one )

基于连接表的单向一对一关联非常少见, 因此这里不讨论.

多对多( many-to-many )

这里使用Student-Course模型

Student配置:

<class name="Student" table="u_student" catalog="hibernateTest_1">
    <id name="id" column="s_id" >
        <generator class="native"></generator>
    </id>
    <property name="name" column="s_name"></property>
    <set name="courses" cascade="save-update" table="student_course">
        <key column="s_id"/>
        <many-to-many class="Course" column="c_id"/>
    </set>
</class>

Course配置:

<class name="Course" table="u_course" catalog="hibernateTest_1">
    <id name="id" column="c_id" >
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
</class>

测试代码:

Student s1 = new Student();
s1.setName("Tom");
Student s2 = new Student();
s2.setName("Jerry");
Course c1 = new Course();
c1.setName("math");
Course c2 = new Course();
c2.setName("physics");

s1.getCourses().add(c1);
s1.getCourses().add(c2);
s2.getCourses().add(c1);
s2.getCourses().add(c2);

session.save(s1);
session.save(s2);

双向关联(Bidirectional associations)

双向关联和单向关联的测试代码部分相同,这里不再贴出测试代码

一对多(one to many)/多对一(many to one)

双向多对一关联 是最常见的关联关系. 下面的例子解释了这种标准的父/子关联关系.

<class name="Order" table="b_order" catalog="hibernateTest">
    <id name="id" column="o_id" >
        <generator class="native"></generator>
    </id>
    <property name="price" column="price"></property>
    <property name="address" column="address"></property>
    <many-to-one name="customer" class="Customer" column="c_id"/>
</class>
<class name="Customer" table="b_customer" catalog="hibernateTest">
    <id name="id" column="c_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
    <set name="orders" inverse="true" cascade="save-update">
        <key column="c_id"/>
        <one-to-many class="Order"/>
    </set>
</class>

一对一(One-to-one)

基于外键的一对一双向关联

<class name="Person" table="b_person" catalog="hibernateTest_1">
    <id name="id" column="p_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="p_name"></property>
    <many-to-one name="idcard" class="IDcard" column="i_id" cascade="save-update"/>
</class>
<class name="IDcard" table="b_idcard" catalog="hibernateTest_1">
    <id name="id" column="i_id">
        <generator class="native"></generator>
    </id>
    <property name="idnum" column="i_idnum"></property>
    <one-to-one name="person" class="Person" property-ref="idcard"/>
</class>

基于主键的一对一关联关系

<class name="Husband" table="b_husband" catalog="hibernateTest_1">
    <id name="id" column="h_id" >
        <generator class="native"></generator>
    </id>
    <property name="name" column="h_name"></property>
    <one-to-one name="wife" cascade="save-update"/>
</class>
<class name="Wife" table="b_wife" catalog="hibernateTest_1">
    <id name="id" column="w_id" >
        <generator class="foreign">
            <param name="property">husband</param>
        </generator>
    </id>
    <property name="name" column="w_name"></property>
    <one-to-one name="husband" cascade="save-update"/>
</class>

这里的测试代码与单向关联时有点不一样, 因此贴出来, 由于generator class="foreign"配置在Wife的配置文件中, 因此在保存Husband进行级联保存之前,需要调用
h.setWife(w);
w.setHusband(h);

这两行代码来维护外键, 比单向关联多一步操作, 当然, 如果调用session.save(w);进行级联保存的话, 也无需调用h.setWife(w);维护外键.

Husband h = new Husband();
h.setName("Lilei");
Wife w = new Wife();
w.setName("Hanmeimei");

h.setWife(w);
w.setHusband(h);

session.save(h);

使用连接表的双向关联(Bidirectional associations with join tables)

一对多(one to many)/多对一(many to one)

<class name="Customer" table="b_customer" catalog="hibernateTest_1">
    <id name="id" column="c_id">
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
    <set name="orders" cascade="save-update" table="_customer_order">
        <key column="c_id"/>
        <many-to-many class="Order" column="o_id" />
    </set>
</class>

需要注意的是这种情况下, inverse="true"可以配置在Collection或者join任意一边, 同时Java代码中也需要对主键进行维护.

<class name="Order" table="b_order" catalog="hibernateTest_1">
    <id name="id" column="o_id" >
        <generator class="native"></generator>
    </id>
    <property name="price" column="o_price"></property>
    <property name="address" column="address"></property>
    <join table="_customer_order" inverse="true">
        <key column="o_id"/>
        <many-to-one name="customer" column="c_id" cascade="save-update"/>
    </join>
</class>

测试代码:

Order o1 = new Order();
o1.setPrice(1888d);
o1.setAddress("Beijing");
Order o2 = new Order();
o2.setPrice(2888d);
o2.setAddress("NewYork");
Customer c = new Customer();
c.setName("Tom");

o1.setCustomer(c);
o2.setCustomer(c);
c.getOrders().add(o1);
c.getOrders().add(o2);

session.save(c);

多对多(many-to-many)

<class name="Course" table="u_course" catalog="hibernateTest_1">
    <id name="id" column="c_id" >
        <generator class="native"></generator>
    </id>
    <property name="name" column="c_name"></property>
    <set name="students" cascade="save-update" table="student_course" inverse="true">
        <key column="c_id"/>
        <many-to-many class="Student" column="s_id"/>
    </set>
</class>
<class name="Student" table="u_student" catalog="hibernateTest_1">
    <id name="id" column="s_id" >
        <generator class="native"></generator>
    </id>
    <property name="name" column="s_name"></property>
    <set name="courses" cascade="save-update" table="student_course">
        <key column="s_id"/>
        <many-to-many class="Course" column="c_id"/>
    </set>
</class>

总结 : 通过上面的例子, 其实可以看出, 在配置中进行双向关联, 在操作Java代码时更加灵活, 可以操作任意一方. 因此, 我倾向于在配置中进行双向关联, Java代码中级联操作(减少资源浪费). 需要注意的是, 在一些情况下,进行级联操作时, 需要对主键进行维护.

参考文献:HIBERNATE - Relational Persistence for Idiomatic Java 1 Hibernate Reference Documentation 3.6.10.Final by Gavin King、Christian Bauer、Max Rydahl Andersen、Emmanuel Bernard、Steve Ebersole and Hardy Ferentschik

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值