问题描述
有些场景下,有些关系不足以拆分出一个实体,但是如果新建一个对象管理会让代码更清晰,这种场景下用到了内嵌对象。
一个Teacher
,三个属性,id
、firstName
、lastName
。
我们可以直接这么写,也可以建一个内嵌的Name
对象,虽然在一个实体中差别不大,但是如果以后有用到name
的场景,可以直接使用该内嵌对象。
解决方案
实现
以下代码省略set
、get
方法:
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Name name;
}
@Embeddable
public class Name {
private String firstName;
private String lastName;
}
启动程序,生成的表结构如下:
所以,映射时直接将内嵌对象中的字段添加到该实体中,然后映射到数据表。
思考
其实说白了就是许多的实体中都有这几个属性,但是根据逻辑关系或复杂度来说不足以单独建立一个实体,所以使用内嵌对象。
就像项目中的不确定度与测量范围一样,虽然属性不少,不足以单独抽出一个实体,但是又有很多实体去用。
根据内嵌的原理,我们可以推断,使用内嵌对象的实体与内嵌对象是一对一的关系时,肯定是可以映射的?那如果映射一个List
呢?因为实际业务场景是不准确度,之前都是一对一使用的该内嵌对象,然后需求变动,需要一对多实现。
尝试多关联
抱着怀疑的态度,我们尝试一下。
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private List names = new ArrayList<>();
}
运行程序,果然报错,应该是我们映射的方式有问题,去查查官方文档。
官方文档
官方文档自然是万能的:Collection Mapping - Hibernate
Using annotations you can map Collections, Lists, Maps and Sets of associated entities using @OneToMany and @ManyToMany. For collections of a basic or embeddable type use @ElementCollection.
使用注解映射`Collection`、`List`、`Map`、`Set`,实体使用`@OneToMany`与`@ManyToMany`,基本类型或内嵌类型使用`@ElementCollection`。
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ElementCollection
private List names = new ArrayList<>();
}
运行程序,查看生成的表结构:
teacher
表:
teacher_names
表:
看着似乎没什么问题,但是设计表会发现teacher_names
是有猫腻的。
内嵌对象集合映射的表没有主键!当然,如果仅仅从teacher
这方面看,这么设计是很合理的。但是并不能满足我们的需求。
思考
StackOverflow
回答的非常好。
内嵌对象没有id
,如果需求复杂,还是用实体吧!内嵌对象只适用于该对象十分简单的情况。
兼容原内嵌
所以,现在的需求变成了原内嵌对象不能动,好多实体用到了,然后又需要将内嵌对象变为实体。原问题就是因为内嵌对象没有id
造成的,填个id
就好了。
@Entity
public class SuperName {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Name name;
@ManyToOne
private Teacher teacher;
}
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "teacher")
private List superNames = new ArrayList<>();
}
再看表结构,没毛病!
总结
用一个新的注解或编码方式时,首要任务是新建一个项目,然后去各种尝试学会它的应用场景,看别人的博客永远没有自己尝试一遍理会的透彻。
只要没有被官方弃用的东西,都有其存在的价值,只是应用场景不同而已,永远没有无用的东西,仅仅是因为我们还没发现。