Published 04 Oct, 2022

Java - Hibernate - Column cannot be null

Category Java
Modified : Nov 30, 2022
81

I'm doing a simple exercise to learn JPA. When I try to delete an entity of type User, which has a Collection of the other entity Score (annotated with @OneToMany) I get this error:

java.sql.SQLIntegrityConstraintViolationException: Column 'user' cannot be null
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:117)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
    at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
    at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1025)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:197)
    ... 20 more

These are my classes:

User.java

@Entity
@Table(name = "user")
public class User 
{
    @Id
    private Integer id;

    @NotNull
    @Size(max = 20)
    private String name;

    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true)
    @JoinColumn(name = "user")
    private Collection<Score> scores;

    public User() {
    }

    public User(Integer id, String name, Collection<Score> scores) {
        this.id = id;
        this.name = name;
        this.scores = scores;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Collection<Score> getScores() {
        return scores;
    }

    public void setScores(Collection<Score> scores) {
        this.scores = scores;
    } 
}

Score.java

@Entity
@Table(name = "score")
public class Score 
{
    @EmbeddedId
    private ScoreId id;

    @NotNull
    private Integer points;

    public Score() {
    }

    public Score(ScoreId id, Integer points) {
        this.id = id;
        this.points = points;
    }

    public ScoreId getId() {
        return id;
    }

    public void setId(ScoreId id) {
        this.id = id;
    }

    public Integer getPoints() {
        return points;
    }

    public void setPoints(Integer points) {
        this.points = points;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj!=null && getClass()==obj.getClass())
        {
            Score other = (Score) obj;
            return Objects.equals(id, other.id) && Objects.equals(points,other.points);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[id =" + id + ",points = " + points;
    }
}

ScoreId.java

@Embeddable
public class ScoreId implements Serializable 
{
    private Integer user;

    @Enumerated(EnumType.STRING)
    private Game game;

    public ScoreId() {
    }

    public ScoreId(Integer user, Game game) {
        this.user = user;
        this.game = game;
    }

    public Integer getUser() {
        return user;
    }

    public void setUser(Integer user) {
        this.user = user;
    }

    public Game getGame() {
        return game;
    }

    public void setGame(Game game) {
        this.game = game;
    }

    public enum Game
    {
        HANGMAN,
        TRIS
    }

    @Override
    public boolean equals(Object obj) {
        if (obj!=null && getClass()==obj.getClass())
        {
            ScoreId other = (ScoreId) obj;
            return Objects.equals(user,other.user) && game==other.game;
        }
        return false;
    }

    @Override
    public int hashCode() 
    {
        return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[user = " + user + ",game = " + game + "]";
    }
}

Main.java

public class Main {

    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("UserJPA");
        EntityManager em = factory.createEntityManager();
        EntityTransaction et = em.getTransaction();

        User demetrio = em.createQuery("SELECT u FROM User u WHERE u.name = 'Demetrio'",User.class).getSingleResult();

        et.begin();
        em.remove(demetrio);
        et.commit();

        em.close();
        factory.close();
    }
}


This is the script to generate db:

CREATE TABLE `user`
(
    id          INT PRIMARY KEY,
    `name`      VARCHAR(20) UNIQUE NOT NULL
);

CREATE TABLE score
(
    `user`      INT,
    game        ENUM("HANGMAN","TRIS"),
    points      INT UNSIGNED NOT NULL,

    PRIMARY KEY(`user`,game),
    FOREIGN KEY (`user`) REFERENCES `user`(id)
                         ON UPDATE CASCADE
                         ON DELETE CASCADE
)

I'm using Hibernate as JPA implementation. I searched for a solution but I did not find anything. Maybe I'm doing something wrong. Can you help me?

Answers

There are 2 suggested solutions here and each one has been listed below with a detailed description. The following topics have been covered briefly such as Java, Hibernate, Jpa. These have been categorized in sections for a clear and precise explanation.

38

I solved by replacing Integer user of ScoreId with User user with a @ManyToOne annotation.
These are my classes:

User.java

@Entity
@Table(name = "user")
public class User 
{
    @Id
    private Integer id;

    @NotNull
    @Size(max = 20)
    private String name;

    @OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true,mappedBy = "id.user")
    private Collection<Score> scores;

    public User() {
    }

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Collection<Score> getScores() {
        return scores;
    }

    public void setScores(Collection<Score> scores) {
        this.scores = scores;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj!=null && getClass()==obj.getClass())
        {
            User other = (User) obj;
            return Objects.equals(id, other.id) && Objects.equals(name, other.name);
        }
        return false;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[id = " + id + ",name = " + name + "]";
    }

    @Override
    public int hashCode() {
        return id!=null ? name!=null ? id.hashCode() + name.hashCode() : 0 : 0;
    }
}



Score.java

@Entity
@Table(name = "score")
public class Score 
{
    @EmbeddedId
    private ScoreId id;

    @NotNull
    private Integer points;

    public Score() {
    }

    public Score(ScoreId id, Integer points) {
        this.id = id;
        this.points = points;
    }


    @Override
    public boolean equals(Object obj) {
        if (obj!=null && getClass()==obj.getClass())
        {
            Score other = (Score) obj;
            return Objects.equals(id,other.id) && Objects.equals(points,other.points);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return id!=null ? points!=null ? id.hashCode()+points.hashCode() : 0 : 0;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[id =" + id + ",points = " + points + "]";
    }
}



ScoreId.java

@Embeddable
public class ScoreId implements Serializable 
{
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="user",referencedColumnName = "id")
    private User user;

    @Enumerated(EnumType.STRING)
    private Game game;

    public ScoreId() {
    }

    public ScoreId(User user, Game game) {
        this.user = user;
        this.game = game;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Game getGame() {
        return game;
    }

    public void setGame(Game game) {
        this.game = game;
    }

    public enum Game
    {
        HANGMAN,
        TRIS
    }

    @Override
    public boolean equals(Object obj) {
        if (obj!=null && getClass()==obj.getClass())
        {
            ScoreId other = (ScoreId) obj;
            return Objects.equals(user,other.user) && game==other.game;
        }
        return false;
    }

    @Override
    public int hashCode() 
    {
        return user!=null ? game!=null ? user.hashCode()+game.hashCode() : 0 : 0;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[user = " + user + ",game = " + game + "]";
    }
}

Database schema is the same.


8

The implementation I see is absolutly correct, allthou it always can be improoved. The db-design is good. The exception you post can simply not exist but it does. The Database must have a problem. Thats why I asked to post the DDL of the table. I trust in your DDL you posted what makes me think: You did everything right.

What I do is I could only guess.

  1. The table's engine is InnoDB but what is the status of the InnoDB-engine? Is it working? Is it active? Use SHOW ENGINE INNODB STATUS to see the status of InnoDB.