Hibernate中一对多配置及操作

表的一对多映射配置

以客户和联系人表为例子:客户是一,联系人是多

1、创建实体类,客户和联系人

2、让两个实体类之间互相表示

(1)在客户实体类中要表示多个联系人

- 一个客户有多个联系人

//在客户实体类里面表示多个联系人,一个客户有多个联系人
	//hibernate中要表示多的数据,使用set集合,不是list集合
	private Set<LinkMan> setLinkMan = new HashSet<LinkMan>();
    public Set<LinkMan> getSetLinkMan() {
		return setLinkMan;
	}
	public void setSetLinkMan(Set<LinkMan> setLinkMan) {
		this.setLinkMan = setLinkMan;
	}

(2)在联系人类中要表示他所属的客户

- 一个联系人只能属于一个客户

//在联系人实体类里面表示所属客户,一个联系人只能属于一个客户
	private Customer customer;
	
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}

3、配置映射文件

(1)一个实体类对应一个映射文件

(2)完成最基本的配置

(3)在映射文件中,配置一对多的关系

- 在客户映射文件中,表示客户的所有联系人

<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
    	<class name="com.demo.entity.Customer" table="t_customer">
    		<id name="cid" column="cid">
    			<generator class="native"></generator>
    		</id>
    	<property name="custName" column="custName"></property>
    	<property name="custLevel" column="custLevel"></property>
    	<property name="custSource" column="custSource"></property>
    	<property name="custPhone" column="custPhone"></property>
    	<property name="custMobile" column="custMobile"></property>
    	
    	<!-- 在客户映射文件中,表示客户的所有联系人 
    		使用set标签表示所有联系人,set标签中有name属性,属性值就是写在客户实体类里表示联系人的set集合的名称
    	-->
    	<set name="setLinkMan">
    	<!-- 一对多建表,有外键
    		hibernate中:双向维护外键,在一和多的那一方都要配置外键
    		column属性值:外键名称
    	 -->
    	 <key column="clid"></key>
    	 <!-- 客户的所有联系人,在class中写联系人实体类的全路径 -->
    	 <one-to-many class="com.demo.entity.LinkMan"/>
    	</set>
    	</class>
    
    </hibernate-mapping>

- 在联系人映射文件中,表示所属客户

 

<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <hibernate-mapping>
    	<class name="com.demo.entity.LinkMan" table="t_linkman">
    		<id name="lkm_id" column="lkm_id">
    			<generator class="native"></generator>
    		</id>
    		
    		<property name="lkm_name" column="lkm_name"></property>
    		<property name="lkm_gender" column="lkm_gender"></property>
    		<property name="lkm_phone" column="lkm_phone"></property>
    		
    		<!-- 表示联系人所属的客户
    			name属性:在联系人实体类中用来连接客户实体类的customer对象
    			class属性:客户实体类的全路径
    			column属性:外键名称,和客户实体类映射文件中的外键对应:clid
    		 -->
    		<many-to-one name="customer" class="com.demo.entity.Customer" column="clid"></many-to-one>
    	</class>
    		
    </hibernate-mapping>

4、创建核心配置文件,将映射配置文件引入到核心配置文件中

	<mapping resource="com/demo/entity/Customer.hbm.xml"/>
	<mapping resource="com/demo/entity/LinkMan.hbm.xml"/>

一对多级联操作

级联操作:

1、级联保存

- 添加一个客户,为这个客户添加联系人

(1)在客户映射文件中进行配置

-- 在客户映射文件里面set标签进行配置

<set name="setLinkMan" cascade="save-update">

(2)创建客户和联系人对象,只需要将联系人对象放到客户对象的set集合中去,最终保存客户对象就可以了

@Test
	public void testAdd(){
		Session session = null;
		Transaction tx= null;
		
		try{
			session = HibernateUtils.getSession();
			tx = session.beginTransaction();
			Customer customer = new Customer();
			customer.setCustName("company1");
			customer.setCustLevel("level1");
			customer.setCustSource("source1");
			customer.setCustPhone("111");
			customer.setCustMobile("135");
			
			LinkMan linkman = new LinkMan();
			linkman.setLkm_name("张三");
			linkman.setLkm_gender("男");
			linkman.setLkm_phone("1333");
			
			customer.getSetLinkMan().add(linkman);
			
			session.save(customer);
			
			tx.commit();
		}
		catch(Exception e){
			tx.rollback();
		}
		finally{
			session.close();
		}
	}

2、级联删除

- 删除一个客户,这个客户的所有联系人也删除

正常情况下,若想要删除一个客户的所有联系人,必须先把所有联系人删除完才可以删除客户,因为客户表和联系人表之间存在外键约束,不能直接删除客户表的数据。

使用hibernate可以解决这一问题

在客户实体类的映射文件中的set标签进行设置

<set name="setLinkMan" cascade="save-update,delete">

删除代码:

@Test
	public void testDelete(){
		Session session = null;
		Transaction tx = null;
		try{
			session = HibernateUtils.getSession();
			tx = session.beginTransaction();
			
			//查询customer对象
			Customer customer = session.get(Customer.class, 1);
			session.delete(customer);
			
			tx.commit();
		}
		catch(Exception e){
			tx.rollback();
		}
		finally{
			session.close();
		}
		
	}

执行结果就是数据库中t_customer表中id为1且在t_linkman中以id=1为外键的记录全部被删除了

控制台输出sql语句:


Hibernate: 
    
    alter table t_linkman 
       add constraint FKjtgu0oocf35ij4fmulu123vwk 
       foreign key (clid) 
       references t_customer (cid)
Hibernate: 
    select
        customer0_.cid as cid1_0_0_,
        customer0_.custName as custName2_0_0_,
        customer0_.custLevel as custLeve3_0_0_,
        customer0_.custSource as custSour4_0_0_,
        customer0_.custPhone as custPhon5_0_0_,
        customer0_.custMobile as custMobi6_0_0_ 
    from
        t_customer customer0_ 
    where
        customer0_.cid=?
Hibernate: 
    select
        setlinkman0_.clid as clid5_1_0_,
        setlinkman0_.lkm_id as lkm_id1_1_0_,
        setlinkman0_.lkm_id as lkm_id1_1_1_,
        setlinkman0_.lkm_name as lkm_name2_1_1_,
        setlinkman0_.lkm_gender as lkm_gend3_1_1_,
        setlinkman0_.lkm_phone as lkm_phon4_1_1_,
        setlinkman0_.clid as clid5_1_1_ 
    from
        t_linkman setlinkman0_ 
    where
        setlinkman0_.clid=?
Hibernate: 
    update
        t_linkman 
    set
        clid=null 
    where
        clid=?
Hibernate: 
    delete 
    from
        t_linkman 
    where
        lkm_id=?
Hibernate: 
    delete 
    from
        t_customer 
    where
        cid=?

一对多修改操作

需求:更改联系人表中的一条数据,使其外键指向客户表中的另一条数据

//演示一对多修改
	@Test
	public void testUpdate(){
		Session session = null;
		Transaction tx = null;
		try{
			session = HibernateUtils.getSession();
			tx = session.beginTransaction();
			
			//查询联系人和客户对象
			Customer customer = session.get(Customer.class, 2);
			LinkMan linkman = session.get(LinkMan.class, 1);
			//设置持久态对象值
			customer.getSetLinkMan().add(linkman);
			linkman.setCustomer(customer);
			
			
			tx.commit();
		}
		catch(Exception e){
			tx.rollback();
		}
		finally{
			session.close();
		}
	}

通过控制台输出可发现一个问题:sql语句中发现对外键的修改发生了两次

Hibernate: 
    update
        t_linkman 
    set
        lkm_name=?,
        lkm_gender=?,
        lkm_phone=?,
        clid=? 
    where
        lkm_id=?
Hibernate: 
    update
        t_linkman 
    set
        clid=? 
    where
        lkm_id=?

原因:在hibernate中,对外键的维护是双向的,在客户实体类和联系人实体类中都需要修改外键

解决方式:可以让其中的一方放弃对外键的维护,在放弃关系维护的那一方的配置文件进行配置

在set标签上添加inverse属性

//inverse:默认值是false,不放弃对关系的维护
<set name="setLinkMan" cascade="save-update,delete" inverse="true">
Hibernate: 
    update
        t_linkman 
    set
        lkm_name=?,
        lkm_gender=?,
        lkm_phone=?,
        clid=? 
    where
        lkm_id=?

结果对外键的维护只更新了一次

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值