4

I've the following one-to-one relation between User and UserSetup entities:

@Entity
class User {

   @OneToOne(mappedBy = "user", optional = false, cascade = ALL)
   private UserSetup setup;

   public User() {
      this.setup = new UserSetup(this);
   }
}

and

@Entity
public class UserSetup {

    @OneToOne(cascade = ALL)
    @JoinColumn(name = "USER_ID", nullable = false, unique = true)
    private User user;

    public UserSetup(User user) {
        this.user = user;
    }
}

It all works well, however if I add @NotNull to setup field in User class and call save on User repository it fails with:

Caused by: javax.persistence.RollbackException: Error while committing the transaction at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:77) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:71) at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ... 64 more Caused by: javax.validation.ConstraintViolationException: Validation failed for classes [User] during update time for groups [javax.validation.groups.Default, ] List of constraint violations:[ ConstraintViolationImpl{interpolatedMessage='may not be null', propertyPath=setup, rootBeanClass=class User, messageTemplate='{javax.validation.constraints.NotNull.message}'} ]

What's going on? In debugger I see that setup field is set. Or maybe @NotNull should not be used with @OneToOne but optional should be used instead?

Opal
  • 81,889
  • 28
  • 189
  • 210

2 Answers2

1

From my understanding of how works Hibernate, that might not be possible, as Hibernate has to save one of the objects first, and when saving the first object the second one cannot be referenced in the database.

What you can do is put the @NotNull annotation to the setup field in the User class, as I understand you may not want to create a User without any setup, and the cascading would take care of removing the linked UserSetup object in case you remove the User.

Vincz777
  • 521
  • 5
  • 12
1

In my opinion, @Notnull can not be used in User for UserSetup. That is because, User needs to be created first, and then the same user's ID would be used to save UserSetup as there is a foreign key constraint on it. Even though code wise, it is looking okay, involvement of DB to create the ID is one important factor here.

gargkshitiz
  • 2,130
  • 17
  • 19
  • Thanks for the answer but is that what you think or you know for sure? – Opal Mar 29 '18 at 09:49
  • It is what I think. Having nullable = false in `@JoinColumn(name = "USER_ID", nullable = false, unique = true)` in UserSetup class makes sense, but having @NotNull for UserSetup in User class seems to create a catch-22 situation. – gargkshitiz Mar 29 '18 at 09:52
  • So you suggest that having either `@NotNull` or `nullable = false` on one side, makes sense? – Opal Mar 29 '18 at 10:06
  • Not exactly, there is a slight difference between these two ways. See https://stackoverflow.com/a/2726224/945214 and https://stackoverflow.com/a/7439544/945214 – gargkshitiz Mar 29 '18 at 10:28