Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

hibernate

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]

like image 423
Feeco Avatar asked Sep 11 '16 04:09

Feeco


1 Answers

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);
});
like image 89
Trevor Avatar answered Oct 20 '22 12:10

Trevor