Каскадное удаление с БД one-to-many Hibernete

319
05 марта 2017, 06:35

Имею две таблицы DEPARTMENT и EMPLOYEE (первая родительская, а вторая - дочерняя). То есть, каждому департаменту соответствует список сотрудников (связь one-to-many). Сотрудники не могут существовать вне департамента, но может существовать департамент без сотрудников. По-этому, мне нужно чтобы при удалении департамента из таблицы DEPARTMENT удалялись соответствующие ему сотрудники с таблицы EMPLOYEE.

Реализовать это нужно с помощью Hibernate. Перепробовал уйму разных вариантов, но при выполнении операции получаю ошибку:

ERROR: Cannot delete or update a parent row: a foreign key constraint fails (`STAFF`.`EMPLOYEE`, CONSTRAINT `FK_ons3ycsifhocods0wpg7gym58` FOREIGN KEY (`department_id`) REFERENCES `DEPARTMENT` (`id`))

Вот исходники:

DepartmentEntity:

@Entity
@Table(name = "DEPARTMENT")
public class DepartmentDataSet implements Serializable  {
@Id
@Column(name = "id", unique = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "name", unique = false, updatable = true, length = 45)
private String name;
@OneToMany(mappedBy = "departmentId", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval=true)
@OnDelete(action = OnDeleteAction.CASCADE)
private Set<EmployeeDataSet> employeesSet;
public DepartmentDataSet() {
}
public DepartmentDataSet(String name) {
    this.name = name;
}
public int getId() {
    return id;
}
public String getName() {
    return name;
}
public void setId(int id) {
    this.id = id;
}
public void setName(String name) {
    this.name = name;
}
public Set<EmployeeDataSet> getEmployeesSet() {
    return employeesSet;
}
public void setEmployeesSet(Set<EmployeeDataSet> employeesSet) {
    this.employeesSet = employeesSet;
}
@Override
public String toString() {
    return "UserDataSet{" + "id=" + id + "', name='" + name + '\'' + '}';
}
}

EmployeeEntity:

@Entity
@Table(name = "EMPLOYEE")
public class EmployeeDataSet  implements Serializable {
    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "department_id", unique = false, updatable = true)
    private int departmentId;
     @Column(name = "age", unique = false, updatable = true)
    private String age;
    @Column(name = "type", unique = false, updatable = false)
    private String type;
    @Column(name = "name", unique = false, updatable = true, length = 25)
    private String name;
    @Column(name = "language", unique = false, updatable = true, length = 25)
    private String language;
    @Column(name = "methodology", unique = false, updatable = true, length = 25)
    private String methodology;
    public EmployeeDataSet() {
    }
    public EmployeeDataSet(String name, String type, String age, int department_id, String methodology,
                           String language) {
        this.setName(name);
        this.setType(type);
        this.setAge(age);
        this.setDepartmentId(department_id);
        this.setMethodology(methodology);
        this.setLanguage(language);
    }
    public EmployeeDataSet(int id, String name, String type, String age, int department_id, String methodology,
                           String language) {
        this.setId(id);
        this.setName(name);
        this.setType(type);
        this.setAge(age);
        this.setDepartmentId(department_id);
        this.setMethodology(methodology);
        this.setLanguage(language);
    }

public int getId() {
    return id;
}
public void setId(int id) {
    this.id = id;
}
public String getAge() {
    return age;
}
public void setAge(String age) {
    this.age = age;
}
public String getType() {
    return type;
}
public void setType(String type) {
    this.type = type;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public int getDepartmentId() {
    return departmentId;
}
public void setDepartmentId(int departmentId) {
    this.departmentId = departmentId;
}
public String getLanguage() {
    return language;
}
public void setLanguage(String language) {
    this.language = language;
}
public String getMethodology() {
    return methodology;
}
public void setMethodology(String methodology) {
    this.methodology = methodology;
}
@Override
public String toString() {
    return "UserDataSet{" +
            "id=" + id +
            ", name='" + name + "', age='" + age +
            ", type='" + departmentId + '\'' +  '}';
}
}   

DepartmentDAO:

   public void removeDepartment(String name) throws HibernateException {
  session.beginTransaction();
  String hql = "delete from DepartmentDataSet where name = :name";
  Query query = session.createQuery(hql);
  query.setString("name", name);
  int rowCount = query.executeUpdate();
  session.getTransaction().commit();
  System.out.println(">>DepartmentDDAO removeDepartment: " + rowCount);
}

Если сделать метод removeDepartment так, как показано ниже, то почему-то все работает. Но мне нужно чтобы мой метод получал имя департамента, а не его id.

 public void removeDepartment(int id) throws HibernateException {
    session.beginTransaction();
    session.delete(session.get(DepartmentDataSet.class, 3));
    session.getTransaction().commit();
}

Буду рад любым подсказкам куда копать)

Answer 1

Аннотация @OneToMany(cascade = CascadeType.ALL) срабатывает только при удалении конкретной записи методом session.delete. У Вас другой случай - идёт удаление результатов SQL-выборки: метод delete не вызывается, а в executeUpdate отрабатывает "чистый" SQL и функции СУБД. JPA в этом процессе уже не участвует и никакие аннотации не уходят в СУБД вместе с SQL-запросом.

Решить задачу можно двумя способами.

  1. Осуществить сначала выборку списка сущностей по имени, а затем пройти по списку и для каждой сущности вызвать session.delete.
  2. Оставить запрос как есть, но указать на уровне СУБД каскадное удаление дочерних записей. Для этого, при создании FOREIGN KEY следует добавить ON DELETE CASCADE.
READ ALSO
Исключение при преобразовании string в int

Исключение при преобразовании string в int

При вводе строки состоящей не только из цифр происходит ошибка

318
Список ListView

Список ListView

Необходимо сделать список из семи дней неделиЯ Id уже дал и нашёл

263
Проверка существования каталога

Проверка существования каталога

Как проверить существует ли каталог?

343
Динамический вызов массивов из xml

Динамический вызов массивов из xml

В xml-файле есть несколько массивов с номерами 0,1,2,3

259