Reputation: 3680
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
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