Hibernate映射集合属性&组件属性(注解版)

本文详细介绍了Hibernate中集合(List、Set、Array、Map)和组件属性的映射方式,包括实体类定义、核心配置引入及代码测试,涵盖了复合主键、外键引用等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:Hibernate映射集合属性

集合大致分为两种:

  • 单列(List,Set,Array):Set比较特殊,因为它没有索引
  • 多列(Map)

注:List集合可以用get(), Array可以用下标,Map集合可以用getKey()

1.1:映射集合属性之List

  • 定义实体类,并描述其关系
  • 引入核心配置文件
  • 使用代码测试
1.1.1:定义实体类,并描述其关系
@Entity //将一个pojo,变成一个实体
@Table
public class Person {

	@Id @Column(name="pid") //跟xml中name属性不一样,这里的name指定的是列名,因为属性名它可以通过注解知道的
	@GeneratedValue(strategy = GenerationType.IDENTITY) //mysql中的主键自增长!
	private Integer id;
	private String name;
	private Integer age;
	@ElementCollection(targetClass = String.class) //指定集合中元素的类型
	@CollectionTable(name = "school_inf",
			joinColumns = @JoinColumn(name="pid",nullable = false)) //表示外键不能为空
	@Column(name = "school_name") //指定表中保存集合元素的列名
	@OrderColumn(name = "list_order") //索引列
	private List<String> schools = new ArrayList<String>();
	
	//省了getter/setter
}
1.1.2:引入核心配置文件
<mapping class="cn.itcast.mappingCollection.set.Person"/>
1.1.3:使用代码测试
@Test
public void testMappingList() {
    Person person = new Person();
    person.setName("wzj");
    person.setAge(22);

    person.getSchools().add("清华小学");
    person.getSchools().add("北大中学");
    person.getSchools().add("哈佛大学");

    session.save(person);
    //这里生成的school_inf表,会用pid和list_order作为联合主键,而且pid还会作为外键引用person的主键!
    //如果生成表中的字段,和预想的完全不符,要看一下数据库中是否之前就存在该表,还有要注意hibernate核心配置文件是否有配置一样的表名导致的!
}

(1)生成表的SQL语句

CREATE TABLE `person` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `school_inf` (
  `pid` int(11) NOT NULL,
  `school_name` varchar(255) DEFAULT NULL,
  `list_order` int(11) NOT NULL,
  PRIMARY KEY (`pid`,`list_order`),
  CONSTRAINT `FKq4nq3ibeg7pcb7jsvmlyetybx` FOREIGN KEY (`pid`) REFERENCES `person` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:其中pid作为外键,引用主表的主键, 并且pid,和list_order组成了一个复合主键
-- 复合主键:在一个表中由两个或两个以上的字段构成的主键,称为复合主键!

(2)生成的表记录
在这里插入图片描述

1.2:映射集合属性之Array

几乎和List的形式差不多!!

1.2.1:定义实体类,并描述其关系
@Entity
@Table
public class Student {

	@Id @Column
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer sid;
	private String name;
	private Integer age;
	@ElementCollection(targetClass=String.class) //集合中元素的类型
	@CollectionTable(name = "school",
   					joinColumns = @JoinColumn(name="sid",nullable = false))//指定外键的名称为sid,并且不能为空
	@Column(name = "school_name") //指定schools属性,在表中的列名
	@OrderColumn(name = "array_order")
	private String[] schools = new String[3];
	
	//省了getter/setter
}
1.2.2:引入核心配置文件
<mapping class="cn.itcast.mappingCollection.array.Student"/>
1.2.3:使用代码测试
@Test
public void testMappingList() {
    Student student = new Student();
    student.setName("wzj");
    student.setAge(22);

    String[] schools = student.getSchools();
    schools[0] = "清华小学";
    schools[1] = "北大中学";
    schools[2] = "哈佛大学";

    session.save(student);
}

(1)生成表的SQL语句

CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `school` (
  `sid` int(11) NOT NULL,
  `school_name` varchar(255) DEFAULT NULL,
  `array_order` int(11) NOT NULL,
  PRIMARY KEY (`sid`,`array_order`),
  CONSTRAINT `FKrt2kife178gvxdtlor829pxut` FOREIGN KEY (`sid`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:使用school(从表)中的外键引用student(主表)中的主键
-- 注:sid即是外键, 也和array_order组成了一个复合主键

(2)生成的表记录
在这里插入图片描述

1.3:映射集合属性之Set

  • 定义实体类,并描述其关系
  • 引入到核心配置文件
  • 使用代码测试
1.3.1:定义实体类,并描述其关系
@Entity
@Table(name = "person_Table")
public class Person {

	@Id @Column(name="id")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer pid;
	private String name;
	private Integer age;
	@ElementCollection(targetClass = String.class) //指定集合元素的类型
	@CollectionTable(name = "car_info",
					joinColumns = @JoinColumn(name="pid",nullable = false))
	@Column(name = "carName")
	private Set<String> carNames = new HashSet<String>();
	
    //省了getter/setter
}
1.3.2:引入到核心配置文件
<mapping class="cn.itcast.mappingCollection.set.Person"/>
1.3.3:使用代码测试
@Test
public void testMappingSet() {
    Person person = new Person();
    person.setName("wzj");
    person.setAge(22);

    person.getCarNames().add("保时捷");
    person.getCarNames().add("兰博基尼");
    person.getCarNames().add("法拉利");

    session.save(person);
}

(1)生成表的SQL语句

CREATE TABLE `person_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `car_info` (
  `pid` int(11) NOT NULL,
  `carName` varchar(255) DEFAULT NULL,
  KEY `FKryng6q8v9qp7d5e1mla7hc1g` (`pid`),
  CONSTRAINT `FKryng6q8v9qp7d5e1mla7hc1g` FOREIGN KEY (`pid`) REFERENCES `person_table` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:因为Set集合没有索引,所以也不需要@OrderColumn, 
-- 注:所以Set生成pid虽然即是主键又是外键,但不想List,Array那种的和索引列组成复合外键了!!

(2)生成的表记录
在这里插入图片描述

1.4:映射集合属性之Map

  • 定义实体类,并描述其关系
  • 引入到核心配置文件
  • 使用代码测试
1.4.1:定义实体类,并描述其关系
@Entity
@Table(name = "t_stu")
public class Student {

	@Id @Column
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer sid;
	private String name;
	private Integer age;
	@ElementCollection(targetClass = Float.class) //对于Map类型的属性:指定的是Value的类型
	@CollectionTable(name = "score_info",
					joinColumns = @JoinColumn(name="sid", nullable = false))
	@MapKeyClass(String.class) //指定Map中key的类型
	@MapKeyColumn(name="suject_name") //指定索引列,也就是key的列名
	@Column(name = "score") //映射保存Map, Value的列名
	private Map<String, Float> scores = new HashMap<String, Float>(); //科目和成绩
	//省了getter/setter
}
1.4.2:引入到核心配置文件
<mapping class="cn.itcast.mappingCollection.map.Student"/>
1.4.3:使用代码测试
@Test
public void testMappingMap() {
    Student student = new Student();
    student.setName("wzj");
    student.setAge(18);

    student.getScores().put("数学", 20F);
    student.getScores().put("语文", 80F);
    student.getScores().put("英语", 80F);

    session.save(student);
    //复合主键:数据库表的主键由两个及以上的字段组成
    //联合主键:多个主键联合形成一个主键的组合。多对多中的中间表就是的!!
}

(1)生成表的SQL语句

CREATE TABLE `t_stu` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `score_info` (
  `sid` int(11) NOT NULL,
  `score` float DEFAULT NULL,
  `suject_name` varchar(255) NOT NULL,
  PRIMARY KEY (`sid`,`suject_name`),
  CONSTRAINT `FK54b26aem2wmdat88q1h7370bd` FOREIGN KEY (`sid`) REFERENCES `t_stu` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 和List和Array类似,因为都是有索引列的,Map的索引列就是key!!!
--- sid不仅是主键还是外键, 并且主键是和索引列组成复合主键!!!

(2)生成的表记录
在这里插入图片描述

1.4.4:上述总结:
  1. 不管哪种类型的集合属性,都需要使用@ElementCollection注解进行映射。

  2. 由于集合属性需要保存到另一个数据表,因此需要为这个表指定一个外键列,用于参照到主键列,

    所以需要@CollectionTable注解映射保存集合属性的表,和@JoinColumn注解映射外键列

  3. List,Array,Map有索引所以需要@OrderColumn或者@MapKeyColumn注解,Set没有所以不需要

  4. 有索引列的,一般都会和外键组成一个复合主键!!

二:Hibernate映射组件属性

什么是组件属性,你这里可以理解不是基本数据类型或包装类,或者String,Date这些。

这里的组件,就是指非持久化类的复合类型(可能还是不太理解,看看例子就知道了)

2.1:映射组件属性的方式一

2.1.1:定义实体类,并描述其关系
@Entity
@Table
public class People {
	
	@Id @Column
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer pid;
	private Integer age;
	//组件属性: name
	private Name name;
	//省了getter/setter
}
@Embeddable //跟@Entity作用一样,表标识,表明这个Name是一个组件!
public class Name {
    //@Column //这里不指定@Column也行,默认列名和属性名一致!
	private String lastName;//姓
	private String firstName;//名
	
	@Parent //owner:主人的意思,@Parent指Name类这个组件,是所属People类的
	private People owner;
	
	public Name() {
		super();
	}
	//省了getter和setter
}

2.1.2:引用到核心配置文件
<mapping class="cn.itcast.mappingComponent.映射组件属性.People"/>
2.1.3:使用代码测试
@Test
public void componentMappingMode1() {
    People people = new People();
    people.setName(new Name("大","帅b"));
    people.setAge(22);

    session.save(people);
}

(1)生成表的SQL语句

CREATE TABLE `people` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `firstName` varchar(255) DEFAULT NULL,
  `lastName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

(2)生成的表记录
在这里插入图片描述

注:组件属性其实也什么特别的,就是把若干个属性封装成一个,到映射的时候再拆分出来!

2.1.4:映射组件属性的方式二
@Entity
@Table
public class People2 {
	
	@Id @Column
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer pid;
	private Integer age;
	//组件属性: name
	@AttributeOverrides({
		@AttributeOverride(name="lastName", column = @Column(name="lastName")),
		@AttributeOverride(name="firstName", column = @Column(name="firstName"))
	})
	private Name name;
	//省了getter/setter
}
@Embeddable
public class Name {
//	@Column //这里不指定@Column也行,默认列名和属性名一致!
	private String lastName;//姓
	private String firstName;//名
	@Parent
	private People owner;
    
	public Name() {
		super();
	}
	//添加有参构造只是为了好赋值而已
	public Name(String lastName, String firstName) {
		super();
		this.lastName = lastName;
		this.firstName = firstName;
	}
    //省了getter/setter
}

(1)生成表的SQL语句

CREATE TABLE `people2` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `firstName` varchar(255) DEFAULT NULL,
  `lastName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

(2)生成的表记录
在这里插入图片描述

注:生成表的SQL语句和记录,和方式一,一模一样。这样方式适合组件中属性较少的场景

2.2:组件属性中有集合

2.2.1:定义实体类,并描述其关系
@Entity
@Table(name = "t_people")
public class People {
	
	@Id @Column
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer pid;
	private Integer age;
	//组件属性
	private Name name;
	//省了getter/setter
}

@Embeddable
public class Name {

	private String lastName;
	private String firstName;
	@Parent
	private People owner; //owner:主人的意思, 使用@Parent注解标识
	
	//组件属性为集合: 这个maps属性没有什么含义,就是单纯演示一下这种效果
	@CollectionTable(name="demoInfo",
					joinColumns = @JoinColumn(name="person_name_id", nullable = false)) 
	@MapKeyClass(String.class) //指定Map类型中key的类型
	@ElementCollection(targetClass = Integer.class) //对于Map类型来说,targetClass指的是value的类型 
	@MapKeyColumn(name="demo_key") //映射Map中key
	@Column(name="demo_value")  //映射Map中的Value
	private Map<String, Integer> demo = new HashMap<String, Integer>();
	
	public Name() {
		super();
	}
	//只是为了快速赋值
	public Name(String lastName, String firstName) {
		super();
		this.lastName = lastName;
		this.firstName = firstName;
	}
}

2.2.2:引入到核心配置文件
<mapping class="cn.itcast.mappingComponent.组件属性中有集合.People"/>
2.2.3:使用代码测试
@Test
public void componentMapping() {
    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("key1", 100);
    map.put("key2", 200);

    Name name = new Name("大", "帅B");
    name.setDemo(map);

    People people = new People();
    people.setAge(22);
    people.setName(name);

    session.save(people);
}

(1)生成表的SQL语句

CREATE TABLE `t_people` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT NULL,
  `firstName` varchar(255) DEFAULT NULL,
  `lastName` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
-- 把组件属性中一些基本数据类型的属性,引入过来了,由于集合会生成另外一张表,因此会使用外键来引入本表的主键
CREATE TABLE `demoinfo` (
  `person_name_id` int(11) NOT NULL,
  `demo_value` int(11) DEFAULT NULL,
  `demo_key` varchar(255) NOT NULL,
  PRIMARY KEY (`person_name_id`,`demo_key`),
  CONSTRAINT `FKdjlg9hxfscnb38ye0ymjyqg9x` FOREIGN KEY (`person_name_id`) REFERENCES `t_people` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 组件中的集合属性,最终生成了另一张表
-- person_name_id即是主键也是外键,并且和Map的索引列,成为了一个复合主键!

(2)生成的表记录
在这里插入图片描述

2.3:集合的元素是组件

2.3.1:定义实体类,并描述其关系
@Entity
@Table(name = "t_student")
public class Student {

	@Id @Column
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Integer sid;
	private String name;
	
	@CollectionTable(name = "t_car",
					joinColumns = @JoinColumn(name="sid", nullable = false))
	@ElementCollection(targetClass = Car.class)
	@OrderColumn(name = "list_order")
//	@Column 如果映射元素是组件属性,那么就不用@Column
	private List<Car> cars = new ArrayList<Car>();//组件属性
	
	@CollectionTable(name = "t_score",
					joinColumns = @JoinColumn(name="sid", nullable = false))
	@MapKeyClass(String.class) //Map中Key的类型
	@ElementCollection(targetClass = Score.class) //Map中Value的类型
	@MapKeyColumn(name="subject")
//	@Column 如果映射元素是组件属性,那么就不用@Column
	private Map<String, Score> scoreMap = new HashMap<String, Score>();//组件属性
	
    //省了getter/setter方法
}

组件属性Car:

@Embeddable
public class Car {

	private String carName;
	private String color;
	@Parent
	private Student owner;
	public Car() {
		super();
	}
}

组件属性Score:

@Embeddable
public class Score {

	private String level; //分数的级别:优秀, 良好, 不及格
	private String ranking; //分数的排名
	@Parent
	private Student owner; //这个Score组件,属于哪个实体!
	
	public Score() {
		super();
	}
	//只是为了好赋值
	public Score(String level, String ranking) {
		super();
		this.level = level;
		this.ranking = ranking;
	}
}
2.3.2:引入到核心配置文件
<mapping class="cn.itcast.mappingComponent.集合属性的元素为组件.Student"/>
2.3.3:使用代码测试
@Test
public void componentMapping() {
    Map<String,Score> scoreMap = new HashMap<String,Score>();
    scoreMap.put("数学", new Score("不及格", "倒数"));
    scoreMap.put("英语", new Score("不及格", "倒数"));

    List<Car> cars = new ArrayList<Car>();
    cars.add(new Car("魅影","粉红色"));
    cars.add(new Car("阿斯顿马丁","粉红色"));

    Student student = new Student();
    student.setName("wzj");
    student.setScoreMap(scoreMap);
    student.setCars(cars);

    session.save(student);
}

(1)生成表的SQL语句

CREATE TABLE `t_student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `t_car` (
  `sid` int(11) NOT NULL,
  `carName` varchar(255) DEFAULT NULL,
  `color` varchar(255) DEFAULT NULL,
  `list_order` int(11) NOT NULL,
  PRIMARY KEY (`sid`,`list_order`),
  CONSTRAINT `FKh832i1jgopvw91lwl2x3q49tt` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:sid即是主键也是外键,因为List集合有索引列,所以sid和索引列(list_order)组成了一个复合主键
-- 注:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!
CREATE TABLE `t_score` (
  `sid` int(11) NOT NULL,
  `level` varchar(255) DEFAULT NULL,
  `ranking` varchar(255) DEFAULT NULL,
  `subject` varchar(255) NOT NULL,
  PRIMARY KEY (`sid`,`subject`),
  CONSTRAINT `FKig6ef2hkc758ki6vqxuvqf5ay` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 类似, sid即是外键也是主键,因为Map也有索引列那就是它的key,所以主键和索引列也会组成一个复合主键
-- 同理:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!

(2)生成的表记录

),
CONSTRAINT FKh832i1jgopvw91lwl2x3q49tt FOREIGN KEY (sid) REFERENCES t_student (sid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
– 注:sid即是主键也是外键,因为List集合有索引列,所以sid和索引列(list_order)组成了一个复合主键
– 注:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!


```sql
CREATE TABLE `t_score` (
  `sid` int(11) NOT NULL,
  `level` varchar(255) DEFAULT NULL,
  `ranking` varchar(255) DEFAULT NULL,
  `subject` varchar(255) NOT NULL,
  PRIMARY KEY (`sid`,`subject`),
  CONSTRAINT `FKig6ef2hkc758ki6vqxuvqf5ay` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 类似, sid即是外键也是主键,因为Map也有索引列那就是它的key,所以主键和索引列也会组成一个复合主键
-- 同理:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!

(2)生成的表记录
在这里插入图片描述
最后来自:虽然帅,但是菜的cxy

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值