delver delver - 2 months ago 30
Java Question

Hibernate attempted to assign id from null one-to-one property

I have two entities:

@Entity
@Table
public class User {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;

@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
private UserDetails userDetails;

}

@Entity
@Table(name="user_details")
public class UserDetails {

@GenericGenerator(name = "generator", strategy = "foreign",
parameters = @Parameter(name = "property", value = "user"))
@Id
@GeneratedValue(generator = "generator")
@Column(unique = true, nullable = false)
private Integer id;

@OneToOne
@PrimaryKeyJoinColumn
private User user;

public UserDetails(User user) {
this.user = user;
user.setUserDetails(this);
}

}


It works if I create a user with a userDetails. But then it creates a UserDetails row and I don't want it. I have to fetch a User from database and add a UserDetails later:

userRepository.findOneById(id).map(user -> {
UserDetails userDetails = user.getUserDetails();
if (userDetails == null)
userDetails = new UserDetails(user);
userDetails.setEmail(email);
userRepository.save(user); //error here
});


Error


org.springframework.orm.jpa.JpaSystemException: attempted to assign id from null one-to-one property [com.app.domain.UserDetails.user]; nested exception is org.hibernate.id.IdentifierGenerationException: attempted to assign id from null one-to-one property [com.app.domain.UserDetails.user]

Answer

The UserDetails object in this case is the owning side of the relationship between a User and the UserDetails

Bidirectional relationships between managed entities will be persisted based on references held by the owning side of the relationship.

Therefore, when you say userRepository.save(user), you're actually trying to save from the child side of the relationship.

You need to create a UserDetailsRepository and invoke the save from that new object.

i.e. here's what the code should look like:

userRepository.findOneById(id).map(user -> {
    UserDetails userDetails = user.getUserDetails();
    if (userDetails == null)
        userDetails = new UserDetails(user); 
     userDetails.setEmail(email);
     userDetailsRepository.save(userDetails);
});