Hibernate,JPA配置集合类型List,Set,Map..(上,Hibernate)

23 篇文章 0 订阅
7 篇文章 0 订阅

通常在Hibernate或JPA中,配置集合多涉及到关联关系的配置,(当泛型为关联对象的类时)
常见的如:
Set List 存在的类中(泛型T不为基础数据类型的包装类)
----------这意味着需要配置一对多或多对多的关联

大多数的情况下,我们能在一对一,一对多,多对多的关系中满足需求,
但有时候则必须配置Map,或Set<基础数据类型>,List<基础数据类型>的映射
所以在此记录一下,以供不时之需

1.Hibernate配置基础类型Set,List

这里自动忽略Set<非基础类型的配置>,因为这些是关联关系配置的范畴,
请参考Hibernate关联配置详解
测试类

public class User {
	
	private Integer ID;
	
	private String UserName;
	
	private Set<String> NickNameSet;
	//省略了getter&setter
}
<?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>

    <class name="HibernateTest.User" table="t_user" lazy="true">
        <id name="ID" column="user_id">
            <generator class="native"/>
        </id>        
        <property name="UserName" type="string" />
        <set name="NickNameSet" table="t_user_nicknames">
        	<!--本质上是建了另一张表,是一种一对多的关系-->
        	<!--设置外键名,这个外键会参照上面的主键user_id-->
        	<key column="userid" ></key>
        	<!--设置set的元素类型,和列名-->
        	<element type="string" column="nickname" ></element>
        </set>
    </class>
</hibernate-mapping>

测试运行:

public class TestMain {
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		Configuration config = new Configuration();
		config.configure();
		config.addClass(User.class);
		
		SessionFactory factory = config.buildSessionFactory();
		Session session = factory.openSession();

		session.beginTransaction();
		
		User user = new User();
		user.setUserName("黃建雄傻逼");
		user.getNickNameSet().add("傻逼");
		user.getNickNameSet().add("廢物");
		user.getNickNameSet().add("壓力怪");
        session.save(user);
		
        session.getTransaction().commit();
		session.close();
	}

}

生成表的代码:

Hibernate: 
    
    create table t_user (
       user_id int identity not null,
        UserName varchar(255),
        primary key (user_id)
    )
Hibernate: 
    
    create table t_user_nicknames (
       userid int not null,
        nickname varchar(255)
    )
Hibernate: 
    --在自动生成的表中添加了外键关联
    alter table t_user_nicknames   
       add constraint FKbfndcewgpmvw7xculx6be6le0 
       foreign key (userid) 
       references t_user

插入的SQL语句:

Hibernate: 
    insert 
    into
        t_user
        (UserName) 
    values
        (?)
Hibernate: 
    insert 
    into
        t_user_nicknames
        (userid, nickname) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_user_nicknames
        (userid, nickname) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        t_user_nicknames
        (userid, nickname) 
    values
        (?, ?)

在这里插入图片描述
List也是同理
只需要稍微修改一下

public class User {
	
	private Integer ID;
	
	private String UserName;
	
	private Set<String> NickNameSet;
	
	private List<String> AddressList;
	
	//省略了getter&setter
}

在hbm.xml中添加配置

<!-- 配置list和上面的set很像,但多了多了一个list-index标签必填---它用来记录list中元素在list中的位置(index) -->
    <list name="AddressList" table="t_user_address">
    	<key column="userid"></key>
    	<list-index column="list_index"></list-index>
    	<element type="string" column="address" ></element>
    </list>

测试中添加:

		user.getAddressList().add("江西南昌");
		user.getAddressList().add("抚州南城");

结果:
在这里插入图片描述

2.Hibernate配置Map

因为Map的Key,和Value为两种泛型,
所以映射Map类型比上面复杂
上述的配置归根结底还是配置特殊的一对多的关系,
但配置Map会根据key,Value的泛型改变关联
简单来说就是
Key,Value泛型决定如何配置Map,

一.Key,Value皆为基础数据类型(包装类)

这是Map映射最简单的情况
同样可以被看做一种特殊的一对多
即一个对象------------多个键值对的一对多的关系

继续上面的用例:
添加map属性

private Map<String, Double> Scores; 
//省略getter&setter

配置

	   <map name="Scores" table="t_user_scores">
	       	<key column="userid"></key>
	       	<map-key column="Subject" type="string" ></map-key>
	       	<element column="Score" type="double"></element>
       </map>

测试(先把表删了再重新运行):

public class TestMain {
	
	
	public static void main(String[] args) {
		
		Configuration config = new Configuration();
		config.configure();
		config.addClass(User.class);
		
		SessionFactory factory = config.buildSessionFactory();
		Session session = factory.openSession();

		session.beginTransaction();
		
		
		
		User user = new User();
		user.setUserName("黃建雄傻逼");
		user.getNickNameSet().add("傻逼");
		user.getNickNameSet().add("廢物");
		user.getNickNameSet().add("壓力怪");
		
		user.getAddressList().add("江西南昌");
		user.getAddressList().add("抚州南城");
		
		user.getScores().put("语文", 59.9);
		user.getScores().put("数学", 59.5);
		user.getScores().put("英语",48.9);
			
        session.save(user);

        session.getTransaction().commit();
		
		session.close();
		
	}
}

载看看建表语句

Hibernate: 
    
    create table t_user_scores (
       userid int not null,
        Subject varchar(255) not null,
        Score double precision,
        primary key (userid, Subject)
    )

也成功将map记录插入到表中

Hibernate: 
    insert 
    into
        t_user_scores
        (userid, Subject, Score) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        t_user_scores
        (userid, Subject, Score) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        t_user_scores
        (userid, Subject, Score) 
    values
        (?, ?, ?)

在这里插入图片描述

二.Key为基础数据类型,Value为引用数据类型

例如:

Map<String,User> map;

这种方式稍微的复杂一些,但任然可以看做是一种特殊的一对多(前提是引用类型中不存在双向关联)
即可以这样理解

Map<String,User> map == Set<User+String属性> set;

所以这就引生出了他的配置方式

首先,我们先添加一个普通的类作为测试的工具

public class Pet {
	
	private Integer ID;
	
	private String Name;
	//省略Getter&Setter
}

<?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>

    <class name="HibernateTest.Pet" table="t_pet" lazy="true">
        <id name="ID" column="Pet_id">
            <generator class="native"/>
        </id>        
        <property name="Name"></property>
    </class>
</hibernate-mapping>

然后,修改配置添加到上面的例子里去

<!-- Map<String,Object>的配置方法,key设置管理类表的外键,使用one-to-many直接配置Value类型 -->
        <map name="Pets" table="t_pet" cascade="all">
        	<!-- 注意:table属性的表名一定要和,该类配置文件配置的表名相同,即Pet的表为t_pet,所以这里的table属性也要为t_pet -->
        	<key column="user_pet_id"></key>
        	<map-key column="t_user_pet" type="string"></map-key>
        	<one-to-many class="HibernateTest.Pet"/>
        </map>

添加该属性到测试类中

public class User {
	
	private Integer ID;
	
	private String UserName;
	
	private Set<String> NickNameSet;
	
	private List<String> AddressList;
	
	private Map<String, Double> Scores; 
	//新增该属性
	private Map<String,Pet> Pets;
	//省略Getter&Setter
}

完整的测试代码:

public class TestMain {
	
	public static void main(String[] args) {
		
		Configuration config = new Configuration();
		config.configure();
		config.addClass(Pet.class);
		config.addClass(User.class);
		
		SessionFactory factory = config.buildSessionFactory();
		Session session = factory.openSession();
		
		session.beginTransaction();

		User user = new User();
		user.setUserName("黃建雄傻逼");
		user.getNickNameSet().add("傻逼");
		user.getNickNameSet().add("廢物");
		user.getNickNameSet().add("壓力怪");
		
		user.getAddressList().add("江西南昌");
		user.getAddressList().add("抚州南城");
		
		user.getScores().put("语文", 59.9);
		user.getScores().put("数学", 59.5);
		user.getScores().put("英语",48.9);
		Pet p1 = new Pet();p1.setName("旺财");
		Pet p2 = new Pet();p2.setName("小黑");
		user.getPets().put("Cat", p2);
		user.getPets().put("dog", p1);
		
        session.save(user);
		
		
        session.getTransaction().commit();
		
		session.close();
		
	}

}
--维护User和Pet关系发出的SQL 语句
Hibernate: 
    update
        t_pet 
    set
        user_pet_id=?,
        t_user_pet=? 
    where
        Pet_id=?
Hibernate: 
    update
        t_pet 
    set
        user_pet_id=?,
        t_user_pet=? 
    where
        Pet_id=?

在这里插入图片描述
注意:
上面的用例设计没有什么意义,我们直接把Key属性设计到Pet里就行了,为什么要多此一举配置一个Map呢
所以正确的设计应该避免在关系映射中使用Map集合

三.Key和Value皆为引用数据类型

当数据Key和Value的数据类型为引用类型式时,
Hibernate配置文件也提供了


的标签,
但笔者查了很多资料都没有看到如何在这种情况进行配置
这里分享一个StackOverFlow上的该问题的回答
https://stackoverflow.com/questions/12296356/hibernate-mapping-of-map-where-key-is-a-part-of-complex-value
所以总结一下,如果能不使用Map形式配置就不使用,因为这样会让实体关系变复杂,
好的设计应该去避免复杂不清楚的关系

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗马苏丹默罕默德

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值