Reputation: 3350
I'm implementing a @ManyToOne bidirectional relationship with a join table using hibernate, but when I'm persisting some data, the hibernate claims that the record in relationship table is being inserted twice, violating the unique constraint, as the error message below shows:
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ERROR: duplicate key value violates unique constraint "tillage_sample_pkey"
Detail: Key (id_tillage, id_sample)=(82, 110) already exists.
I have the following tables:
When I create a Tillage object, I fill with a Sample. In the Sample Object, I point with the Tillage object, creating a "double binding".
I guess that this "double bind" is causing the trouble, as Tillage/Sample relationship is persisted by hibernate when is saving the Tillage and repeating the step when it tries to persist the Tillage inside the Sample (which is the same tillage object).
Here Goes my code, to help you to understand my issue:
Tillage.java
@Entity
@Table(name = "tillage")
public class Tillage implements Serializable {
private static final long serialVersionUID = 3605331584324240290L;
@Id
@GeneratedValue(generator = "tillage_id_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "tillage_id_seq", sequenceName = "tillage_id_seq", allocationSize = 1)
private Integer id;
@Column(name = "name")
private String name;
// Other simple attributes
@ManyToOne
@JoinColumn(name = "id_farm")
@JsonBackReference
private Farm farm;
// This relation is the problematic one
@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "tillage_sample",
joinColumns = { @JoinColumn(name = "id_tillage") },
inverseJoinColumns = {@JoinColumn(name = "id_sample") })
private List<Sample> sampleList;
// Although similar, this one is doing OK
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "tillage_owner",
joinColumns = { @JoinColumn(name = "id_tillage") },
inverseJoinColumns = {@JoinColumn(name = "id_owner") })
private List<Owner> ownerList;
// getters & setters
}
Sample.java
@Entity
@Table(name = "sample")
public class Sample implements Serializable {
private static final long serialVersionUID = 7064809078222302493L;
@Id
@GeneratedValue(generator = "sample_id_seq", strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "sample_id_seq", sequenceName = "sample_id_seq", allocationSize = 1)
private Integer id;
@Column(name = "name")
private String name;
// Other simple attributes
// This completes the relation Tillage-Sample
@ManyToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "tillage_sample",
joinColumns = { @JoinColumn(name = "id_sample") },
inverseJoinColumns = {@JoinColumn(name = "id_tillage") })
private Tillage tillage = new Tillage();
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinTable(name = "sample_sample_item",
joinColumns = { @JoinColumn(name = "id_sample") },
inverseJoinColumns = {@JoinColumn(name = "id_sample_item") })
private List<SampleItem> sampleItemList;
// Getters and Setters
}
SomeService.java
...
@Override
public Tillage toTillage(TillageDTO dto) {
Tillage tillage = new Tillage();
tillage.setName(dto.getNameTillage());
// Fill the samples of the tillage
for(ArrSample sample : dto.getSamples().getArrSample()){
Sample s = new Sample();
s.setName(sample.getName());
// Setting the tillage in the Sample object
s.setTillage(tillage);
// Fill the items of the sample
for(Array arr : sample.getAreas().getArray()){
SampleItem si = new SampleItem();
si.setProduction(Double.parseDouble(arr.getProduction()));
// Double binding between sample and sampleItem
si.setSample(s);
s.getSampleItemList().add(si);
}
// Adding a sample to Tillage
tillage.getSampleList().add(s);
}
return tillage;
}
public void save(TillageDTO dto){
Tillage t = this.toTillage(dto);
// The error occurs when we persist the data
// The entityManager is Autowired by Spring and works in other places
entityManager.persist(tillage);
}
Upvotes: 1
Views: 1838
Reputation: 692181
That's not a bidirectional OneToMany. That's too separate unidirectional associations using the same join table.
In a bidirectional association, one side must be the inverse of the other side. For a OneToMany, the One side must be the inverse side:
@OneToMany(mappedBy = "tillage", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private List<Sample> sampleList;
Upvotes: 2