5

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.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
hamed
  • 7,939
  • 15
  • 60
  • 114
  • How are user positions created and used usually? This is important, because the cascade property should be seen as part of the service layer and not as part of the how do I map something. – mh-dev May 12 '15 at 08:25

1 Answers1

3

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);
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911