0

I am using JPA with hibernate. I have a 1-to-1 parent child relationship (the child is optional), with the id shared between the two and a foreign key relationship on the child table. My entities look like this:

parent:

public class LogItemEntity {
...

    @OneToOne(cascade={CascadeType.ALL}, mappedBy = "logItem", orphanRemoval=true, optional=true)
    @PrimaryKeyJoinColumn(referencedColumnName="ral_id")
    private LogAdditionalRequirement additionalRequirement;
...
}

child:

public class LogAdditionalRequirement {
...
    @Id
    @GeneratedValue(generator = "foreign")
    @GenericGenerator(name = "foreign", strategy = "foreign", parameters = { @Parameter(name = "property", value = "logItem") })
    @Column(name = "ral_id")
    private Long id;

    @OneToOne(optional=false)
    @PrimaryKeyJoinColumn(referencedColumnName="id")
    private LogItemEntity logItem;
...
}

When inserting a new object, the id for the parent is generated from a sequence and the cascade operation copies it onto the child. But the sql insert for the child is placed in the action queue of the session before the sql insert for the parent, and so it fails with a constraint violation on the foreign key:

ERROR o.h.util.JDBCExceptionReporter - ERROR: insert or update on table "rar_log_additional_requirement" violates foreign key constraint "fk_rar_ral_id"
Detail: Key (ral_id)=(70150) is not present in table "ral_log".

So how can I make the insert of the parent happen first?

This must be a pretty common usage, so I assume I'm doing something wrong, but I don't see what it is. I originally had the mappedBy attribute on the child side. I think that's wrong, but swapping it round made no difference.

  • Can you show the code where you create the new Entity and the code which persists it? – Alan Hay May 19 '14 at 11:11
  • I have also just noticed that you have defined @PrimaryKeyJoinColumn on both sides which doesn't seem right. See here for a simple example. http://vard-lokkur.blogspot.co.uk/2011/05/onetoone-with-shared-primary-key.html – Alan Hay May 19 '14 at 11:33

1 Answers1

0

One solution could be to remove the cascade "cascade={CascadeType.ALL}"

More on this subject here

Danix
  • 1,947
  • 1
  • 13
  • 18
  • Thanks, but if I do that, won't I have to save the child object explicitly? Otherwise I get a TransientObjectException on flush(). The parent actually contains several children like this one, most of which are optional, so that means adding a bunch of extra code which I wanted to avoid. Incidentally, the behaviour of collections, using @ElementCollection, seems quite different, they get persisted on a flush without the need for any specific handling at all. Maybe I can just (ab)use a singleton collection? – user3399293 May 19 '14 at 11:03
  • Yes, see http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection: "There is no cascade option on an ElementCollection, the target objects are always persisted, merged, removed with their parent." The issue you are experiencing is most likely with the way you construct and save the new instance. Post the code for this. – Alan Hay May 19 '14 at 11:19
  • I'm using Spring JpaRepository, so I set up the references between parent and child and call JpaRepository.save() thus: logItemEntity.setAdditionalRequirement(additionalRequirement); additionalRequirement.setLogItem(logItemEntity); jpaRepository.save(logItemEntity); – user3399293 May 19 '14 at 11:29
  • I didn't know what you want to achive, so that's why I have this answer, but: [This](http://stackoverflow.com/questions/10551485/hibernate-cascade-type) might help you. – Danix May 19 '14 at 11:38
  • I want a parent entity, with an optional child, and I want to persist the parent and child (if it exists) with a single method call. – user3399293 May 19 '14 at 11:51
  • Were you able to figure this out? – theprogrammer Mar 25 '22 at 19:01