I’m using Hibernate 6.2.5.Final
with an entity like this:
@Entity
@Table(name = "sen_sensor_group")
public class SensorGroup implements Serializable {
@Id
@Column(name = "id")
@GenericGenerator(
name = "sen_sensor_group_id_seq",
strategy = "enhanced-sequence",
parameters = {
@Parameter(name = "sequence_name", value = "sen_sensor_group_id_seq"),
@Parameter(name = "optimizer", value = "pooled-lo"),
@Parameter(name = "increment_size", value = "50")})
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sen_sensor_group_id_seq")
private Long id;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "sen_sensor_group_sensor",
joinColumns = @JoinColumn(name = "sensor_group_id", nullable = false),
inverseJoinColumns = @JoinColumn(name = "sensor_id", nullable = false)
)
@OrderBy("name")
private Set<Sensor> sensors = new LinkedHashSet<>();
// Other fields...
}
When updating the group, I get a “duplicate key value violates unique constraint” error if I reuse the set in the group when some of the items added already are part of the group. It seems like Hibernate is trying to re-insert items that had already existed in the set.
However, if I use a new set and add the already existing items the group persists correctly. Why does re-using the set cause existing items to be inserted?
For example, this does not work:
@Transactional
public SensorGroup updateSensorGroup(String username, SensorGroup sensorGroup) {
var updatedSensorGroup = getSensorGroup(username, sensorGroup.getSensorGroupId());
updatedSensorGroup.setName(sensorGroup.getName());
// Clearing the set, then re-adding items causes constraint violation if items added
// were already in the set previously.
updatedSensorGroup.getSensors().clear();
for (var sensor :sensorGroup.getSensors()) {
var fetchedSensor = getSensor(username, sensor.getSensorId());
updatedSensorGroup.getSensors().add(fetchedSensor);
}
return updatedSensorGroup;
}
This does work as expected without error:
@Transactional
public SensorGroup updateSensorGroup(String username, SensorGroup sensorGroup) {
var updatedSensorGroup = getSensorGroup(username, sensorGroup.getSensorGroupId());
updatedSensorGroup.setName(sensorGroup.getName());
// Using a new set and replacing the original works
Set<Sensor> sensorsToKeep = new HashSet<>();
for (var sensor : sensorGroup.getSensors()) {
var fetchedSensor = getSensor(username, sensor.getSensorId());
sensorsToKeep.add(fetchedSensor);
}
updatedSensorGroup.setSensors(sensorsToKeep);
return updatedSensorGroup;
}