I have 2 Oracle tables in a 1:M relationship:
EVENT(ID, NAME, DATE)
EVENT_LOG(ID, EVENT_ID, COMPLETED)
EVENT has PK=ID
EVENT_LOG has PK=ID and FK=EVENT_ID on EVENT.ID
I want to use Spring JPA to persist this data to database, so I build my entities with @OneToMany
and @ManyToOne
annotations like below (some details omitted for clarity):
@Entity
@Table(name = "EVENT")
public class EventEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@Column(name = "NAME")
private String name;
@Column(name = "DATE"")
private OffsetDateTime date;
@OneToMany(mappedBy = "eventEntityDetails", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<EventLogEntity> eventLogs;
...
}
@Entity
@Table(name = "EVENT_LOG")
public class EventLogEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@Column(name = "EVENT_ID")
private long eventId;
@Column(name = "COMPLETED")
private int completed;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "E_ID", referencedColumnName = "ID")
private EventEntity eventEntityDetails;
// ...
}
In order to persist my EVENT and EVENT_LOG, I have this method. It receives EntityDto object which I map to a new instance of Entity and then I create new EventLogEntity, set its COMPLETED
value and call repository to save my event.
At this stage, I cannot set the EventLog.EVENT_ID as at this stage EVENT.ID has not been generated, so my expectation is that hibernate takes care of that for me. However that turns to be wrong and I think I am missing something either in this method or in my @OneToMany
and @ManyToOne
annotations above in my entities:
private EventEntity saveEvent(EventDto eventDto) {
EventEntity eventEntity = new EventEntity();
ModelMapper modelMapper = new ModelMapper();
modelMapper.map(eventDto, eventEntity);
List<EventLogEntity> eventLogs = new ArrayList<EventLogEntity>();
EventLogEntity eventLogEntity = new EventLogEntity();
eventLogEntity.setCompleted(1);
eventLogs.add(eventLogEntity);
eventEntity.setEventtLogs(eventLogs);
EventEntity storedEvent = eventRepository.saveAndFlush(eventEntity);
return storedEvent;
}
PROBLEM
The above call to safeAndFlush()
will save my Event and EventLog to their tables, however EVENT_LOG.EVENT_ID (which is the FK to EVENT.ID) is always set 0 instead of being set to the value in EVENT.ID.
I would expect it to be set to the ID of EVENT like in example below:
EVENT(1, 'open_door', 20220210T11:55:10)
EVENT_LOG(1, 1, 1)
, but instead, I get:
EVENT(1, 'open_door', 20220210T11:55:10)
EVENT_LOG(1, 0, 1)
CodePudding user response:
I think you have to assign the EventEntity
object to the EventLogEntity
before flushing:
EventLogEntity eventLogEntity = new EventLogEntity();
eventLogEntity.setCompleted(1);
eventLogEntity.setEventEntityDetails(eventEntity);
eventLogs.add(eventLogEntity);
See if that helps.
Update: I think what you want is the following:
@Entity
@Table(name = "EVENT")
public class EventEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@OneToMany(mappedBy = "event", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<EventLogEntity> eventLogs;
...
}
@Entity
@Table(name = "EVENT_LOG")
public class EventLogEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name = "ID")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EVENT_ID")
private EventEntity event;
}
Notice a few things here:
- I removed the
referencedColumnName
info because by default the primary key of the referencing table is used, which is fine in our case - I removed the explicit
EVENT_ID
column which you declared as part of the class. This column will be created automatically as part of attaching the@ManyToOne
annotation on theevent
field. - I renamed the
eventEntityDetails
field simply toevent
I am pretty sure the solution will work! Please let me know.