Issue
I'm using hibernate in my spring mvc application and have a question about cascade. I see to many similar questions about it, but none of them can answer my question. Suppose I have User
and UserPosition
objects. User
has a collection of UserPosition
and also has one UserPosition
as the default position. Structure is look like this:
User:
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Collection<UserPosition> userPositionCollection;
public Collection<UserPosition> getUserPositionCollection() {
return userPositionCollection;
}
public void setUserPositionCollection(Collection<UserPosition> collection) {
this.userPositionCollection = collection;
}
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "default_User_Position_ID", referencedColumnName = "id")
private UserPosition defaultUserPosition;
public UserPosition getDefaultUserPosition() {
return defaultUserPosition;
}
public void setDefaultUserPosition(UserPosition defaultUserPosition) {
this.defaultUserPosition = defaultUserPosition;
}
UserPosition:
@JoinColumn(name = "user_id", referencedColumnName = "id")
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@OneToOne(fetch = FetchType.LAZY, mappedBy = "defaultUserPosition", cascade = CascadeType.PERSIST)
private User defaultUserPosition;
public User getDefaultUserPosition() {
return defaultUserPosition;
}
public void setDefaultUserPosition(User defaultUserPosition) {
this.defaultUserPosition = defaultUserPosition;
}
Now, my question is what's the best practice to use cascade for saving related objects?. In fact, I confused with these three solutions:
Solution 1:
User user = new User();
//some setters and getters
UserPosition userPosition = new UserPosition();
//some setters and getters
List<UserPosition> positionList = new ArrayList<>();
positionList.add(userPosition);
user.setDefaultUserPosition(userPosition);
user.setUserPositionCollection((Collection<UserPosition>) positionList );
session.persist(user)
Solution 2:
User user = new User();
//some setters and getters
UserPosition userPosition = new UserPosition();
//some setters and getters
userPosition.setUser(user);
userPosition.setDefaultUserPosition(user);
session.persist(userPosition)
Solution 3(Combination of two previous solutions):
User user = new User();
//some setters and getters
UserPosition userPosition = new UserPosition();
//some setters and getters
List<UserPosition> positionList = new ArrayList<>();
positionList.add(userPosition);
user.setDefaultUserPosition(userPosition);
user.setUserPositionCollection((Collection<UserPosition>) positionList );
userPosition.setUser(user);
userPosition.setDefaultUserPosition(user);
session.persist(user);
This is very important for me, so please help me. Which solution is correct and where should be cascade
property? Thank you for your time.
Solution
The User
is the parent entity and cascading always propagates from Parent to Child entities.
Therefore, the User associations become:
@OneToMany(mappedBy = "user",
fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
orphanRemoval = true)
private Collection<UserPosition> userPositionCollection;
but for the default position, the User becomes the Child
of the association:
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "default_User_Position_ID", referencedColumnName = "id")
private UserPosition defaultUserPosition;
In the UserPosition
class is the other way around:
@JoinColumn(name = "user_id", referencedColumnName = "id")
@ManyToOne(fetch = FetchType.LAZY)
private User user;
and
@OneToOne(fetch = FetchType.LAZY,
mappedBy = "defaultUserPosition",
cascade = CascadeType.PERSIST)
private User defaultUserPosition;
Then you also have to add the following utility methods that always synchronize both sides. These go into the User
class:
public void addUserPosition(UserPosition userPosition) {
userPositionCollection.add(userPosition);
userPosition.setUser(this);
}
public void addDefaultUserPosition(UserPosition userPosition) {
defaultUserPosition = userPosition;
userPosition.setDefaultUserPosition(this);
}
The persisting logic becomes:
User user = new User();
//some setters and getters
UserPosition userPosition = new UserPosition();
//some setters and getters
user.addUserPosition(userPosition);
user.setDefaultUserPosition(userPosition);
session.persist(user);
Answered By - Vlad Mihalcea
Answer Checked By - Gilberto Lyons (JavaFixing Admin)