Reputation: 194
I'm trying to add a new Employee-entity via my REST-api to the database. The Employee-entity contains a City property. This is a ManyToOne relationship. When I insert a new employee with a NEW (not existing) city it works fine. However, when I add a new employee with an existing city I get this error.
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1000' for key 'PRIMARY'
My CascadeType is set to ALL. When I change it to SAVE_UPDATE it works fine when I insert a new Employee with an EXISTING city, but it does not work when I insert a new employee with a new city.
Employee:
package be.pxl.backend.entity;
import java.util.Date;
import java.util.List;
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.hibernate.annotations.*;
import org.hibernate.annotations.CascadeType;
@Entity
@Table(name="Employees")
public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int employee_id;
private String username;
private String password;
private String salt;
private String surName;
private String name;
private String street;
@Column(name="house_nr")
private String houseNr;
@ManyToOne
@Cascade (value={CascadeType.MERGE, CascadeType.PERSIST})
private City city;
private Date date_employment;
private String mobile_phone;
private String telephone_number;
private String email;
private String sex;
private Boolean status;
@OneToMany(mappedBy="employee")
private List<Login> logins;
@OneToMany(mappedBy = "employee")
private List<SensorUsage> usages ;
public List<Login> getLogins() {
return logins;
}
public Boolean getStatus() {
return status;
}
public int getEmployee_id() {
return employee_id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getSalt() {
return salt;
}
public String getSurName() {
return surName;
}
public String getName() {
return name;
}
public String getStreet() {
return street;
}
public String getHouseNr() {
return houseNr;
}
public City getCity() {
return city;
}
public Date getDate_employment() {
return date_employment;
}
public String getMobile_phone() {
return mobile_phone;
}
public String getTelephone_number() {
return telephone_number;
}
public String getEmail() {
return email;
}
public String getSex() {
return sex;
}
public void setStatus(boolean status) { this.status = status; }
}
City:
package be.pxl.backend.entity;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name="Cities")
public class City {
@Id
private String postal_code;
private String city;
@OneToMany(mappedBy = "city")
private List<Destination> destinations;
@OneToMany(mappedBy = "city")
private List<Employee> employees;
public String getPostal_code() {
return postal_code;
}
public String getCity() {
return city;
}
}
This is where I persist:
package be.pxl.backend.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import be.pxl.backend.entity.*;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query("from Employee e where e.username = :username")
Employee getEmployeeByUsername(@Param("username")String username);
}
Help would be appreciated!
Upvotes: 2
Views: 8454
Reputation: 3733
In order to set a bidirectional Many to One association you'll need to do this:
On the source/owning entity (The entity with the foreign key) you, of course, annotate it with @ManyToOne
annotation and also annotate it with the @JoinColumn
annotation. In your case, this is how it should look like on Employee entity:
@Entity
@Table(name="Employees")
public class Employee {
@ManyToOne
@JoinColumn(name = "your_fk_column")
private City city;
}
And on your City entity do this:
@Entity
@Table(name="Cities")
public class City {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "city")
private List<Employee> employees;
}
One of the actions that CascadeType.ALL
will do in reference to your example is when you'll try to persist/save employee it'll do the same for the associated city because of that CascadeType.ALL
.
Now, if you'll try to save a new employee with an existing city it's pretty obvious that you'll get the error that you're getting, because when you try to save a new employee Hibernate will try to save the existing city, but you can't save the same records with the same PK twice that is why Hibernate complains about:
Duplicate entry '1000' for key 'PRIMARY'
If you want after all the same city records with different primary keys, just before saving the entity, set the city PK to null.
Or, just move the cascade to the city entity like I did. Like that whenever you'll try to save an employee the city won't get persist as well.
Or just change the cascade type from all, to every cascade type except persist.
Upvotes: 4