
Usually, when we write a Many-To-Many relationship it is between 2 entities. Sometimes, it could happen that we have an entity which has a field which is a set of enum. In this case, we need to approach the problem differently and Spring comes to help.
Let’s see an example where we have two classes: Person and Skill (e.g. swimming, running, etc).
The following code shows what the situation is when Person and Skill are both entities.
@Entity
public class Person {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "person_skill", joinColumns = {
@JoinColumn(name = "person_id")
}, inverseJoinColumns = {
@JoinColumn(name = "skill_id")
})
private Set <Skill> skillSet;
}
@Entity
public class Skill {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
To use this mapping, you would have 3 tables. You can create them with the following SQL code.
CREATE TABLE `person` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `skill` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `person_skill` ( `person_id` BIGINT(20) NOT NULL, `skill_id` BIGINT(20) NOT NULL, PRIMARY KEY (`person_id`, `skill_id`), INDEX `skill_fk_idx` (`skill_id` ASC), CONSTRAINT `person_fk` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `skill_fk` FOREIGN KEY (`skill_id`) REFERENCES `skill` (`id`) ON DELETE CASCADE ON UPDATE CASCADE );
The following code shows what the situation is when Person is an entity and Skill is an enum.
@Entity
public class Person {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ElementCollection(targetClass = Skill.class)
@CollectionTable(name = "person_skill", joinColumns = @JoinColumn(name = "person_id"))
@Enumerated(EnumType.STRING)
@Column(name = "skill_name")
private Set <Skill> skillSet;
}
public enum Skill {
RUNNING,
SWIMMING
}
To use this mapping, you would have only 2 tables, because Skill is not an entity and would not have its own table. You can create them with the following SQL code.
CREATE TABLE `person` ( `id` BIGINT(20) NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE `person_skill` ( `person_id` BIGINT(20) NOT NULL, `skill_name` VARCHAR(45) NOT NULL, PRIMARY KEY (`person_id`, `skill_name`), CONSTRAINT `person_fk` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE CASCADE ON UPDATE CASCADE );
As you can see here, you don’t have the table skill because Skill is not an entity but only an enum; you only have to create the table which represents the relationship between Person and Skill.
Furthermore, since we added the annotation @Enumerated(EnumType.STRING), Spring Data will save the name of the entity in the database (look, we put a VARCHAR column). If you prefer, you could use EnumType.ORDINAL and Spring Data will save the ordinal value of the entity (1,2,3,etc..), so change the column to accept a numeric value.
That’s it!
