Boaris
Boaris

Reputation: 5236

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]

Upvotes: 9

Views: 22866

Answers (2)

Ariel-.
Ariel-.

Reputation: 11

the answer of was very helpful to me, is tricky to understand how hibernate works... at least for me (nooby :D)

Upvotes: -3

Trevor
Trevor

Reputation: 1137

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);
});

Upvotes: 11

Related Questions