`
oham_一1一
  • 浏览: 51317 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Hibernate使用——一对多关联示例

阅读更多

一对多关联

 

首先举一例:阵型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是层级的连锁操作。在一对多的关联中将多的一方设为主控方去维护关联,有助性能优化。

 

 

 

 

 

 

 

 

 

 

  • 大小: 7 KB
分享到:
评论

相关推荐

    Hibernate使用——入门

    - **一对多**:`@ManyToOne`和`@OneToMany`注解用于一对多关系,`@OneToMany`通常配合`@JoinColumn`使用。 - **多对多**:`@ManyToMany`处理多对多关系,需要中间表,可通过`@JoinTable`定义。 **学习资源推荐** - ...

    Hibernate总结——课程管理

    本教程将深入探讨如何使用Hibernate来实现一个简单的课程管理系统,涵盖多对多关联映射以及CRUD操作。 ### Hibernate概述 Hibernate是一个开源的ORM框架,它允许开发者使用Java对象来表示数据库中的记录,从而避免...

    Hibernate ORM - 一对多双向组合关联关系

    这个标题表明我们要讨论的是Hibernate ORM框架中的一种特定的数据关系映射——一对多双向组合关联。在关系型数据库中,一对多关联意味着一个父实体可以与多个子实体相对应,而双向则表示这种关系是相互的,即父实体...

    jpa之使用hibernate示例代码

    6. **关联映射**:JPA允许定义实体之间的关联,如一对一(@OneToOne),一对多(@OneToMany),多对一(@ManyToOne)和多对多(@ManyToMany)。这些关联可以通过属性或集合进行映射。 7. **懒加载和即时加载**:...

    Hibernate数据关联映射与继承策略

    2. **一对多关联(One-to-Many)**:一个实体可以与数据库表中的多个记录关联。通常使用集合类型(如 List, Set)来存储关联对象,通过在子类的一方定义外键实现。 3. **多对一关联(Many-to-One)**:与一对多相反...

    Hibernate教程10_关系映射之多对一单向关联

    本教程主要聚焦于Hibernate中的一个关键概念——关系映射,特别是多对一单向关联的实现。这种关联类型常出现在数据库设计中,比如一个部门可以有多名员工,但一个员工只属于一个部门。 首先,我们要理解多对一关系...

    hibernate多对多关联的问题

    ### Hibernate多对多关联问题详解 #### 背景与问题描述 在使用Hibernate框架处理实体间多对多关系时,经常会遇到一个棘手的问题——如何有效地管理中间关联表(如`role_popedom`),特别是在执行删除和更新操作时...

    Java封装自联表一对多

    在Java编程中,"封装自联表一对多"是一个重要的概念,主要应用于关系数据库与对象模型的映射,尤其是在使用ORM(Object-Relational Mapping)框架如Hibernate或MyBatis时。这一概念涉及到数据结构、面向对象编程以及...

    Hibernate学习

    #### 一对多关联映射单向(one-to-many) - **对象模型**:定义了一个实体类与其多个子实体类之间的关系。 - **Classes实体类**:表示班级信息。 - **Students实体类**:表示学生信息。 - **Student映射文件**:...

    Hibernate 框架测试版本

    Hibernate 支持多种关系映射,如一对一(@OneToOne)、一对多(@OneToMany)、多对一(@ManyToOne)和多对多(@ManyToMany)。通过这些注解,你可以定义实体之间的关联关系。 10. **实用工具** Hibernate 提供了...

    hibernate3.6 文档(pdf 格式)

    - **单向 Set 基础关联**:讲解单向一对多关联的实现方法。 - **操作关联**:演示如何通过代码操纵实体间的关联。 - **值集合**:介绍如何映射集合属性,如 Set 和 List。 - **双向关联**:讨论双向一对多关联的概念...

    HIBERNATE doc_document_官方文档_4.3.6_final_2014_8

    - **Hibernate教程**: 包括第一部分——第一个Hibernate应用程序,第二部分——映射关联,第三部分——EventManager Web应用程序。每部分都提供了详细的步骤和代码示例,让开发者能够通过实践来学习Hibernate的使用...

    Hibernate5实例程序

    Hibernate支持多种关系映射,如一对一(`@OneToOne`)、一对多(`@OneToMany`)、多对一(`@ManyToOne`)和多对多(`@ManyToMany`)。每种关系映射都有相应的配置方法。 11. **懒加载(Lazy Loading)** 通过`@...

    Hibernate开发指南

    - **一对多关联**: - **单向一对多**: 父对象持有子对象集合的引用。 - **双向一对多**: 子对象反过来也持有父对象的引用。 - **多对多关联**: 通常需要通过中间表来维护关系。 ##### 8. 数据访问 - **POJO ...

    hibernate的_映射、三态、脏数据、Session缓存

    例如,在上述示例中,`&lt;set&gt;`元素定义了一个班级与学生的一对多关系,其中`&lt;key&gt;`元素指定了外键`class_id`与班级表之间的关联。 - **一对多(One-to-Many)映射**:一对多关系是实体间常见的一种关联关系。在上述...

    hibernate.jar

    5. 支持关联映射:一对多、一对一、多对多等各种关联关系的映射。 6. 插件扩展:例如,Hibernate Search允许对数据库进行全文搜索。 六、最佳实践 - 避免在循环中使用Session,以免引发内存泄漏。 - 使用...

    Hibernate映射关系配置:XML方式和注解方式

    3. **关联映射**:XML映射文件中可以定义一对多、一对一、多对多等各种关系,比如使用`&lt;set&gt;`, `&lt;one-to-one&gt;`, `&lt;many-to-many&gt;`等元素。 **注解方式** 1. **@Entity**:这个注解标记一个Java类为Hibernate实体,...

    hibernate课程源码.

    4. **006_Hibernate_OneToMany**: 这部分讲解了一对多(OneToMany)关系映射,这是最常见的对象关系映射形式。通过实例,你将学会如何在实体之间建立和管理这种关系。 5. **008_Hibernate_ExtendsORM**: 这可能涉及...

    北大青鸟6.0Y2课程使用Hibernate开发系统-4~6

    6. **一对多、多对一、多对多关联映射**:了解并实践不同关系类型的实体间关联,如集合的使用,以及关联的配置。 7. **缓存机制**:Hibernate内置了一级缓存和二级缓存,课程会讲解如何配置和使用,以提高数据访问...

    hibernate-3.2.6下载

    在文件名称列表中,"hibernate-3.2"可能是压缩包的一部分,可能包含多个与Hibernate 3.2.6相关的文件和子目录,如lib目录下的各种jar文件,包括Hibernate的核心库、JDBC驱动、JTA实现等;还可能有文档、示例代码或者...

Global site tag (gtag.js) - Google Analytics