I have a problem with Hibernate. I am using Spring 2.7.5. I have three entities.
- Alarm,
- AlarmList,
- ListAlarmJoinTable.
Alarm and AlarmList are in a MtoM relation. The tricky part is that they are not referencing each other, but they both have a OneToMany reference to the ListAlarmJoinTable.
Here are the classes:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "alarm")
public class Alarm {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer alarmId;
@Column(unique = true)
String name;
private Long time;
private Integer code;
private Integer priority;
private String source;
private String description;
private String codeAsAsString;
private String priorityAsString;
private Integer dmId;
private Boolean internal;
private Integer instnaceindex;
@OneToMany(orphanRemoval = true, cascade = {CascadeType.REMOVE, CascadeType.MERGE})
private List<ListAlarmJoinTable> alarmLists;
@Override
public String toString() {
return "JsonAlarm [time=" time ", code=" code ", priority="
priority ", source=" source ", description="
description ", alarmId=" alarmId ", codeAsAsString="
codeAsAsString ", priorityAsString=" priorityAsString
", dmId=" dmId ", internal=" internal
", instnaceindex=" instnaceindex "]";
}
}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@ToString
@Table(name = "alarm_list")
public class AlarmList {
@Id
private String name;
@OneToMany(orphanRemoval = true, cascade = {CascadeType.REMOVE, CascadeType.MERGE})
private List<ListSequenceJoinTable> alarmSequences;
@OneToMany(orphanRemoval = true, cascade = {CascadeType.REMOVE, CascadeType.MERGE})
private List<ListAlarmJoinTable> alarms;
}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Table(name = "list_alarms_join_table")
public class ListAlarmJoinTable {
@EmbeddedId
private AlarmListId id;
private int position;
}
@Embeddable
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AlarmListId implements Serializable {
private Integer alarmId;
private String listId;
}
When Hibernate creates the schema and tables, it creates the following tables:
"alarm", "alarm_list", "alarm_alarm_lists" , "alarm_list_alarms", "list_alarms_join_table".
What I actually need are these: "alarm", "alarm_list", "list_alarms_join_table".
Now, at first I thought it was the dialect, so I tried out every MySQL dialect and it didn't work. I even ran maven clean install
(even though I knew that wouldn't change anything).
For further information this is my application.properties:
CodePudding user response:
The mapping is wrong because JPA cannot guess that ListAlarmJoinTable
is essentially a join table (with an extra property). JPA sees your setup and thinks the relations Alarm
→ AlarmListId
and AlarmList
→ AlarmListId
have nothing to do with the fields of the AlarmListId
, that you intended to be foreign keys.
Change the AlarmListId
as follows to make the relation explicit:
@Embeddable
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AlarmListId implements Serializable {
@ManyToOne(optional=false, fetch=LAZY)
private Alarm alarm;
@ManyToOne(optional=false, fetch=LAZY)
private AlarmList list;
// You MUST implement hashCode() and equals(), probably Lombok's
// @EqualsAndHashCode is enough but please check the semantics!!!
}
Now, you have to use mappedBy
in the @OneToMany
annotations over Alarm.alarmLists
and AlarmList.alarms
. I think the value should be:
@OneToMany(..., mappedBy = "id.alarm")
private List<ListAlarmJoinTable> alarmLists;
// AND:
@OneToMany(..., mappedBy = "id.list")
private List<ListAlarmJoinTable> alarms;
The mappedBy
property will help JPA understand that these are just the reverse sides of the same relation.