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.
@Entitypublic 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;}@Entitypublic 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.
@Entitypublic 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!