I am currently writing a fairly "dumb" ETL process. I call it dumb because the process runs nightly, digest all of the data (even if it hasn't change), and persist it. My hope is to keep it simple.
I've been using Hibernate v6.1.7 to define my entities and persist them. Since the entities may already exist in my database, I'm using merge to persist the entity.
public static void main(String[] args){
BaseballGame game = new BaseballGame();
BaseballWeather weather = new BaseballWeather();
game.setGameId(12345L);
game.setWeather(weather);
weather.setTemperature(70.0);
weather.setGame(game);
Session session = Hibernate.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
session.merge(game);
transaction.commit();
session.close();
}
This works fine for simple entities that don't have any complex relationship and for entities that have a ManyToOne relationship.
I'm running into problems when persisting an entity that has a OneToOne relationship where the child owns the key. Here are some trivial examples of entities that exhibit this problem.
@Entity
@Table(name = "baseball_game")
public class BaseballGame {
@Id
private Long gameId;
@OneToOne(mappedBy = "game", cascade = CascadeType.MERGE)
private BaseballWeather weather;
public void setGameId(Long gameId) {
this.gameId = gameId;
}
public void setWeather(BaseballWeather weather) {
this.weather = weather;
}
}
@Entity
@Table(name = "baseball_weather")
public class BaseballWeather {
@Id
private Long id;
private Double temperature;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "game_id")
@MapsId
private BaseballGame game;
public void setTemperature(Double temperature) {
this.temperature = temperature;
}
public void setGame(BaseballGame game) {
this.game = game;
}
}
If I run the main code from above, it will succeed on the first run. But once the baseball_weather exists, running merge produces the following error.
Exception in thread "main" jakarta.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [x.y.z.BaseballWeather#12345]
The error message is correct, I'm manually creating a version of the BaseballWeather class that contains the same ID as an object already stored in the session. But I'm not seeing this behavior with the parent class or with other entities that don't have this OneToOne relationship. In those cases objects I create manually will still be merged without error.
I was under the impression that specifying the cascade type to "Merge" would, well, cascade the merge operation. I've tried substituting in the other cascade types (Persist, All, etc..) and none have been able to persist the object if it doesn't exist or update if it does.
Is anyone aware of how I can update my entities to support both persisting and updating via the merge method without running into errors?