TheWebCoder TheWebCoder - 3 years ago 177
Java Question

Why does Hibernate allow me to insert a null value on a foreign key constraint?

I am experimenting with jpa and hibernate relations. I'm using a table named users and a table named emails. A user can have many emails.

When I run my Spring boot application along with the following code I get one email record in my h2 database. The email_address of this record is testAddress and the user_username column of this record is null. The user_username column is listed as a foreign key on the emails table. My question is, why is emailRepository.save(email1) successful when there is no corresponding user in the database?

@Entity
@Table(name = "emails")
public class Email {

@Id
private String emailAddress;

@ManyToOne
private User user;

...

}

@Entity
@Table(name = "users")
public class User {

@Id
private String username;

@OneToMany(mappedBy="user", cascade=CascadeType.ALL, orphanRemoval=true)
private Set<Email> emails;

...

}

public interface UserRepository extends JpaRepository<User, String> {

}

public interface EmailRepository extends JpaRepository<Email, String> {

}

@Component
public class UserRepositoryCommandLineRunner implements CommandLineRunner {

@Autowired
private EmailRepository emailRepository;

public void run(String... args) throws Exception {
Email email1 = new Email();
email1.setEmailAddress("testAddress");
emailRepository.save(email1);
}

}

Ish Ish
Answer Source

Take a look at the documentation of the JoinColumn annotation: https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/JoinColumn.html#nullable()

It is mentioned:

If the JoinColumn annotation itself is defaulted, a single join column is assumed and the default values apply.

Since you did not specify a JoinColumn in your ManyToOne mapping, then Hibernate would assume the default JoinColumn. If you take a look at the JoinColumn.nullable attribute, it is defaulted to true. Thus, when Hibernate generates your schema, the foreign key column is by default NULLABLE.

You may need to explicitly add a @JoinColumn annotation on top of your @ManyToOne mapping and set its nullable attribute to false.

@ManyToOne
@JoinColumn(nullable=false)
private User user;

This way, it'll throw out an error when you try to insert email without a user.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download