一对多关联
首先举一例:阵型cancan的人找lulu阵型里的人做心灵pk,无奈cancan阵型里的人与lulu阵型实力相距甚远。。。于是提出cancan阵型里的人可以群K lulu阵型里的单个人,当然,接受单挑。
在hibernate的映射中,一对多关联分为单向一对多和双向一对多关联。
单向一对多
TLulu.java:
package learnHibernate.bean; import java.io.Serializable; import java.util.List; import java.util.Set; public class TLulu implements Serializable { private static final long serialVersionUID = -252962688967803016L; private int id ; private String name; private String sixthSense; private TOham oh; private Set<TCancan> cs; 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 TOham getOh() { return oh; } public void setOh(TOham oh) { this.oh = oh; } public String getSixthSense() { return sixthSense; } public void setSixthSense(String sixthSense) { this.sixthSense = sixthSense; } public Set<TCancan> getCs() { return cs; } public void setCs(Set<TCancan> cs) { this.cs = cs; } }
TCancan.java
package learnHibernate.bean; public class TCancan { private int id; private String name; private String think; private TOham oh; private int rivalId; 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 getThink() { return think; } public void setThink(String think) { this.think = think; } public TOham getOh() { return oh; } public void setOh(TOham oh) { this.oh = oh; } public int getRivalId() { return rivalId; } public void setRivalId(int rivalId) { this.rivalId = rivalId; } }
TLulu.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="learnHibernate.bean"> <class name="TLulu" table="t_lulu"> <id name="id" column="id" type="java.lang.Integer"> <generator class="foreign"> <param name="property">oh</param> </generator> </id> <one-to-one name="oh" class="TOham" constrained="true"/> <property name="name" column="name" type="java.lang.String" /> <property name="sixthSense" column="sixthsense" type="java.lang.String" /> <!-- 这里用set存储多个TCancan,因为是一对多的关联, set中必须指定“多”方的关联表以及关联字段 --> <set name="cs" table="t_cancan" cascade="all"> <key column="rivalid" /> <one-to-many class="TCancan" /> </set> </class> </hibernate-mapping>
TCancan.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="learnHibernate.bean"> <class name="TCancan" table="t_cancan"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native" /> </id> <one-to-one name="oh" class="TOham" property-ref="can" /> <property name="name" column="name" type="java.lang.String" /> <property name="think" column="think" type="java.lang.String" /> <property name="rivalId" column="rivalid" type="java.lang.Integer" /> </class> </hibernate-mapping>
注意,在做保存更新操作的时候,为了保持关联关系,只能通过主控方(此处为被外键引用方:TLulu)对被动方(持有关联外键方:TCancan)进行操作。所以这里就可能出现一个问题,当关联字段不允许为null时,hibernate在进行创建或更新关联关系的时候可能出现约束违例。
现在想对某个TLulu的人再分配一个TCancan对手:
TLulu lu = (TLulu)session.get(TLulu.class, new Integer(9)); TCancan can = new TCancan(); can.setName("Can3"); can.setThink("Inversion not exists"); lu.getCs().add(can); session.save(lu); tx.commit();
此时问题出现了:当执行到session.save(lu)时,hibernate执行如下sql:
Hibernate: insert into t_cancan (name, think, rivalid) values (?, ?, ?)
于是抛了一个异常:org.hibernate.exception.ConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`hibernate/t_cancan`, CONSTRAINT `FK_t_cancan_1` FOREIGN KEY (`rivalid`) REFERENCES `t_lulu` (`id`))。
这是因为此时关联是单向的关联关系是由TLulu对象维持,而TCancan并不知自己与哪个TLulu相关联,所以在save(lu)的时候去保存Tcancan,只能想先给rivalid插个空值,其实当执行tx.commit()的时候,hibernate会执行一条update语句,因为save的时候是saveTLulu对象的,所以hibernate会将TLulu的对象自身的id赋值给TLulu的对象中的TCancan,在事务提交的时候,hibernate会发现这一变化,于是就执行一条sql语句。
针对上述,现在将TCancan.hbm.xml中 的rivalid映射属性去掉,执行save的时候就不会试图将null保存给t_cancan了,此处可以对t_cancan表做些修改,给rivalid设置默认值。这样就避免了上述异常。
但问题是为了插一条记录执行两个sql语句,效率并不高,这里完全只需一条sql能搞定,只要想法使得执行save(lu)的时候让can对象知道如何获取lu对象的id并以其作为自身的rivalId的值。
于是,双向的一对多关联来了。
双向一对多
双向的一对多关联其实是“一对多”与“多对一”关联的组合。也就是说在主控方配置一对多映射的同时,也需要在被控方配置多对一的映射。
将TCancan.hbm.xml修改如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="learnHibernate.bean"> <class name="TCancan" table="t_cancan"> <id name="id" column="id" type="java.lang.Integer"> <generator class="native" /> </id> <one-to-one name="oh" class="TOham" property-ref="can" /> <property name="name" column="name" type="java.lang.String" /> <property name="think" column="think" type="java.lang.String" /> <many-to-one name="lu" class="TLulu" cascade="none" outer-join="auto" update="true" insert="true" access="property" column="rivalid" not-null="true" /> </class> </hibernate-mapping>
TCancan.java修改如下:
package learnHibernate.bean; public class TCancan { private int id; private String name; private String think; private TOham oh; private TLulu lu; 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 getThink() { return think; } public void setThink(String think) { this.think = think; } public TOham getOh() { return oh; } public void setOh(TOham oh) { this.oh = oh; } public TLulu getLu() { return lu; } public void setLu(TLulu lu) { this.lu = lu; } }
执行代码修改如下,加了一行can.setLu(lu):
TLulu lu = (TLulu)session.get(TLulu.class, new Integer(10)); TCancan can = new TCancan(); can.setName("Can3"); can.setThink("Inversion not exists"); can.setLu(lu); lu.getCs().add(can); session.save(lu); tx.commit();
结果输出:
Hibernate: insert into t_cancan (name, think, rivalid) values (?, ?, ?) Hibernate: update t_cancan set rivalid=? where id=?
。。。结果不对,不应该输出两个sql,应该是一个insert的sql才对。。。
原因是这里的关联主控方还是TLulu,在hibernate的一对多的映射关联概念中,关联关系的维护室主控方负责的,虽然执行代码中已经can.setLu(lu)这样了,但由于TCancan不是主控方,所以,在映射的层面上,TCancan不会因为有了can.setLu(lu)而主动将lu的id赋值到自身的rivalid。
于是此时需要把TCancan作为关联的主控方,有它负责维护关联关系。
对TLulu.hbm.xml的set节点做下修改:
<set name="cs" table="t_cancan" cascade="all" inverse="true"> <key column="rivalid" /> <one-to-many class="TCancan" /> </set>
inverse设置为true,就行了。意思是我TLulu本来的关联主控方放弃主控角色的责任,交由TCancan被控方负责维护关联。
重新执行代码,结果:
Hibernate: insert into t_cancan (name, think, rivalid) values (?, ?, ?)
算是成事了。
注意的是inserve与cascade的区别,inverse是指关联关系的控制方向,而cascade是层级的连锁操作。在一对多的关联中将多的一方设为主控方去维护关联,有助性能优化。
相关推荐
- **一对多**:`@ManyToOne`和`@OneToMany`注解用于一对多关系,`@OneToMany`通常配合`@JoinColumn`使用。 - **多对多**:`@ManyToMany`处理多对多关系,需要中间表,可通过`@JoinTable`定义。 **学习资源推荐** - ...
本教程将深入探讨如何使用Hibernate来实现一个简单的课程管理系统,涵盖多对多关联映射以及CRUD操作。 ### Hibernate概述 Hibernate是一个开源的ORM框架,它允许开发者使用Java对象来表示数据库中的记录,从而避免...
这个标题表明我们要讨论的是Hibernate ORM框架中的一种特定的数据关系映射——一对多双向组合关联。在关系型数据库中,一对多关联意味着一个父实体可以与多个子实体相对应,而双向则表示这种关系是相互的,即父实体...
6. **关联映射**:JPA允许定义实体之间的关联,如一对一(@OneToOne),一对多(@OneToMany),多对一(@ManyToOne)和多对多(@ManyToMany)。这些关联可以通过属性或集合进行映射。 7. **懒加载和即时加载**:...
2. **一对多关联(One-to-Many)**:一个实体可以与数据库表中的多个记录关联。通常使用集合类型(如 List, Set)来存储关联对象,通过在子类的一方定义外键实现。 3. **多对一关联(Many-to-One)**:与一对多相反...
本教程主要聚焦于Hibernate中的一个关键概念——关系映射,特别是多对一单向关联的实现。这种关联类型常出现在数据库设计中,比如一个部门可以有多名员工,但一个员工只属于一个部门。 首先,我们要理解多对一关系...
### Hibernate多对多关联问题详解 #### 背景与问题描述 在使用Hibernate框架处理实体间多对多关系时,经常会遇到一个棘手的问题——如何有效地管理中间关联表(如`role_popedom`),特别是在执行删除和更新操作时...
在Java编程中,"封装自联表一对多"是一个重要的概念,主要应用于关系数据库与对象模型的映射,尤其是在使用ORM(Object-Relational Mapping)框架如Hibernate或MyBatis时。这一概念涉及到数据结构、面向对象编程以及...
#### 一对多关联映射单向(one-to-many) - **对象模型**:定义了一个实体类与其多个子实体类之间的关系。 - **Classes实体类**:表示班级信息。 - **Students实体类**:表示学生信息。 - **Student映射文件**:...
Hibernate 支持多种关系映射,如一对一(@OneToOne)、一对多(@OneToMany)、多对一(@ManyToOne)和多对多(@ManyToMany)。通过这些注解,你可以定义实体之间的关联关系。 10. **实用工具** Hibernate 提供了...
- **单向 Set 基础关联**:讲解单向一对多关联的实现方法。 - **操作关联**:演示如何通过代码操纵实体间的关联。 - **值集合**:介绍如何映射集合属性,如 Set 和 List。 - **双向关联**:讨论双向一对多关联的概念...
- **Hibernate教程**: 包括第一部分——第一个Hibernate应用程序,第二部分——映射关联,第三部分——EventManager Web应用程序。每部分都提供了详细的步骤和代码示例,让开发者能够通过实践来学习Hibernate的使用...
Hibernate支持多种关系映射,如一对一(`@OneToOne`)、一对多(`@OneToMany`)、多对一(`@ManyToOne`)和多对多(`@ManyToMany`)。每种关系映射都有相应的配置方法。 11. **懒加载(Lazy Loading)** 通过`@...
- **一对多关联**: - **单向一对多**: 父对象持有子对象集合的引用。 - **双向一对多**: 子对象反过来也持有父对象的引用。 - **多对多关联**: 通常需要通过中间表来维护关系。 ##### 8. 数据访问 - **POJO ...
例如,在上述示例中,`<set>`元素定义了一个班级与学生的一对多关系,其中`<key>`元素指定了外键`class_id`与班级表之间的关联。 - **一对多(One-to-Many)映射**:一对多关系是实体间常见的一种关联关系。在上述...
5. 支持关联映射:一对多、一对一、多对多等各种关联关系的映射。 6. 插件扩展:例如,Hibernate Search允许对数据库进行全文搜索。 六、最佳实践 - 避免在循环中使用Session,以免引发内存泄漏。 - 使用...
3. **关联映射**:XML映射文件中可以定义一对多、一对一、多对多等各种关系,比如使用`<set>`, `<one-to-one>`, `<many-to-many>`等元素。 **注解方式** 1. **@Entity**:这个注解标记一个Java类为Hibernate实体,...
4. **006_Hibernate_OneToMany**: 这部分讲解了一对多(OneToMany)关系映射,这是最常见的对象关系映射形式。通过实例,你将学会如何在实体之间建立和管理这种关系。 5. **008_Hibernate_ExtendsORM**: 这可能涉及...
6. **一对多、多对一、多对多关联映射**:了解并实践不同关系类型的实体间关联,如集合的使用,以及关联的配置。 7. **缓存机制**:Hibernate内置了一级缓存和二级缓存,课程会讲解如何配置和使用,以提高数据访问...
在文件名称列表中,"hibernate-3.2"可能是压缩包的一部分,可能包含多个与Hibernate 3.2.6相关的文件和子目录,如lib目录下的各种jar文件,包括Hibernate的核心库、JDBC驱动、JTA实现等;还可能有文档、示例代码或者...