samshers
samshers

Reputation: 3680

Hibernate Overwiriting Column values with NULL?

On Inserting/Saving the last element, hibernate is overwriting the earlier element's ManyToOne Column with NULL. Below is detailed description.

I am creating few "State" objects and persisting them in to DB -

        Country usa = new Country ("USA", "330000000");
        State mi = new State("MI", "11000000", usa);
        State ca = new State("CA", "39900000", usa);
        State fl = new State("FL", "21300000", usa);

        countryRepository.save(usa); 
        stateRepository.save(mi); 
        stateRepository.save(ca); 
        stateRepository.save(fl);

Hibernate is persisting the "State" objects into DB as expected, until it reaches persisting the last "State" object. This is where it is triggering the below query and inserting null value to country field.

2019-09-09 11:45:37.390 DEBUG 9600 --- [  restartedMain] org.hibernate.SQL                        : 
    update
        state 
    set
        country_name=null 
    where
        country_name=?
2019-09-09 11:45:37.390 TRACE 9600 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [USA]

So on the DB side, it has caused the country field of all previously persisted States(rows in table) to be set to null.
Then it is persisting the last state -

2019-09-09 11:45:39.649 DEBUG 9600 --- [  restartedMain] org.hibernate.SQL                        : 
    insert 
    into
        state
        (country_name, population, name) 
    values
        (?, ?, ?)
2019-09-09 11:45:39.650 TRACE 9600 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [USA]
2019-09-09 11:45:39.650 TRACE 9600 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [21300000]
2019-09-09 11:45:39.650 TRACE 9600 --- [  restartedMain] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [FL]

The resulting DB table is as below - you can see null value for country_name of CA and MI, but not for FL which is the last Saved State.

mysql> select * from state;
+------+------------+--------------+
| name | population | country_name |
+------+------------+--------------+
| CA   | 39900000   | NULL         |
| FL   | 21300000   | USA          |
| MI   | 11000000   | NULL         |
+------+------------+--------------+

The java entity objects are as below:
State entity -

@Table(name="state")
@Entity
public class State {

    @Id
    @Column(name="name")
    String name;
    @Column(name="population") 
    String population;  

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="state_name")
    List<City> cities;

    @ManyToOne (cascade=CascadeType.ALL, fetch=FetchType.LAZY) 
    Country country;  
    //getters and setters 

and the Country entity -

@Table(name="country")
@Entity
public class Country {

    @Id
    @Column(name="name")
    String name;

    @Column(name="population")
    String population;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinColumn(name="country_name")
    List<State> states; 
    //getters and setters

Any hint's of why this behavior of overwriting country field with null value for every state except for the last. I am not expecting the null value for country for other states.

Upvotes: 0

Views: 2235

Answers (1)

PaulD
PaulD

Reputation: 499

If you have CascadeType.ALL you don't need to do all this

countryRepository.save(usa); 
stateRepository.save(mi); 
stateRepository.save(ca); 
stateRepository.save(fl);

I'd recommend to make sure you add the states to the list of states in your country in your states' constructor and then just persisting the country. Also I would not use FetchType.EAGER and rather fetch when you do actually need it since it can cause a large amount of SQL statements

Upvotes: 2

Related Questions