Complex JPA persist order issue
-
11-10-2019 - |
Question
I'm working on a project with some unusual entity relations which i'm having problems persisting with JPA. There are two relevant objects; User and let's call the other X. User has a one-to-many AND two one-to-one relations to X. It basicly looks like this
[User entity]
@OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true)
private List<X> xList;
@OneToOne
@JoinColumn(name = "active_x1_id")
private X activeX1;
@OneToOne
@JoinColumn(name = "active_x2_id")
private X activeX2;
[X entity]
@ManyToOne()
@JoinColumn(name="user_id")
private User user;
When persisting a new user, I also want to persist two x entities (one for activeX1 and one for activeX2) in a single transaction. Jpa handles this abit weird, the log looks like this:
INSERT INTO X VALUES (...) // x1
INSERT INTO USERS VALUES (...)
INSERT INTO X() VALUES (...) // x2
UPDATE USERS SET ...
UPDATE X VALUES (...) // updates x1
This makes it impossible to use NOT NULL constraints in the database. Is there any better way to handle these multiple relationships? Or a way to control which order JPA persists objects? JPA really seems to explicitly try to work against me in this operation. Any help would be appreciated.
Solution 2
Solved with the use of EntityManager.flush method, forcing JPA to persist the user first.
user.setProperties(properties);
em.persist(user);
em.flush();
X x1 = new X(user);
user.setActiveX1(x1);
X x2 = new X(user);
user.setActiveX2(x2);
I still have to allow null values on the activeX-column of user, but that is alright as I can at least force not null on X.
OTHER TIPS
Why don't you just use @NotNull annotation? I don't think there is a way to change persist order. You have to do it manually. Something like this,
User user = ...;
if ( user.getActiveX1().getId() == null ) {
entityManager.persist( user.getActiveX1() );
} else {
entityManager.merge( user.getActiveX1() );
}
if ( user.getActiveX2().getId() == null ) {
entityManager.persist( user.getActiveX2() );
} else {
entityManager.merge( user.getActiveX2() );
}
if ( user.getId() == null ) {
entityManager.persist( user );
} else {
entityManager.merge( user );
}