Hibernate OneToOne: forced to choose between option = false or cascade?
To keep the transferred data small, I created two objects for my files in the database. fileheader
save some general information about files and fileblob
, including fileId
blob. Often I only need to ask a general one fileinformations
.
So I need to load fileblobs
lazily.
As I learned in this discussion and this discussion , this can be achieved with optional = false
. It works great to load fileblobs
lazily. Unfortunately, this affects the cascade conservation.
So here is my attribute in Fileh.class
for blob:
@OneToOne(mappedBy = "fileh", targetEntity = Fileblob.class, fetch = FetchType.LAZY, optional = false)
@org.hibernate.annotations.Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK })
private Fileblob fileblob;
If now save a fileh
with attached fileblob
, this error is thrown:
org.hibernate.id.IdentifierGenerationException: Thrown empty identifier for: class Fileblob
if i change from "identity" to "increment" strategy this error comes up:
ERROR SqlExceptionHelper:147 - Cannot add or update a child row: a foreign key constraint fails (`CORE`.`FILEBLOB`, CONSTRAINT
FKFILEBLOB412557
FOREIGN KEY (ID
) REFERENCESfileh
(ID
)) Request: insert into CORE.fileblob
(fileblob
,ID
) values (?,?)
So there is a problem with generating id ... If I now disable cascading save my attribute looks like this.
@OneToOne(mappedBy = "fileh", targetEntity = Fileblob.class, fetch = FetchType.LAZY, optional = false)
private Fileblob fileblob;
To save now I have to call
persistentSession.saveOrUpdate(fileh);
persistentSession.saveOrUpdate(fileblob);
This is not only what should be done CascadeType.SAVE_UPDATE
? Why does this work for "manual cascading" but not automatically?
Ps: To complete my example here, copy at fileblob.class
@PrimaryKeyJoinColumn
@OneToOne(targetEntity=Fileh.class, fetch=FetchType.LAZY)
@org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK})
@JoinColumns({ @JoinColumn(name="`ID`", referencedColumnName="`ID`", unique=true, nullable=false) })
private Fileh fileh;
@Column(name="`ID`", nullable=false, insertable=false, updatable=false, unique=true)
@Id
@GeneratedValue(generator="FILEBLOB_FILEHID_GENERATOR")
@org.hibernate.annotations.GenericGenerator(name="FILEBLOB_FILEHID_GENERATOR", strategy="foreign", parameters=@org.hibernate.annotations.Parameter(name="property", value="fileh"))
private int filehId;
source to share
Well, first I would use JPA cascading instead of hibernate one:
@OneToOne(mappedBy = "fileh", fetch = FetchType.LAZY, optional = false)
private Fileblob fileblob;
And Fileblob, I think your config might be a little simpler without these generators, etc. (assuming the id should actually be a foreign key pointing to Fileh.id).
@Column(name="`ID`", nullable=false, unique=true)
@Id
private int filehId;
@JoinColumn(name = "id", referencedColumnName = "id")
@OneToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST})
@MapsId
private Fileh fileh;
source to share
I ran into the same problem and have been trying to solve it for days! It turns out that this is a problem that has been in the Hibernate bug system for over 2 years now!
While the answer here helps solve the problem, we are forced to abandon the use of Persist Cascade from the parent Entity (downside as well as mappedBy side )
Please see this link: https://hibernate.atlassian.net/browse/HHH-9670
If you would like to apply lazy loading to a OneToOne relationship and can execute the Persist cascade as usual, please leave a comment to show your concern about the issue!
source to share