有序Hibernate列表的唯一约束违例

时间:2012-01-07 21:37:53

标签: java hibernate jpa unique-constraint

如果我尝试从Task通过TaskList方法删除removeTask,我会有以下实体并获得例外。

@Entity
public class TaskList extends GenericModel {

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) 
  @OrderColumn(name="position", nullable=false)
  public List<Task> tasks = new ArrayList<>();

  // ...

  public void removeTask(Task task) {
    tasks.remove(task);
  }
}

@Entity
public class Task extends Model {

  @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinColumn(name="task_id")
  private List<Reservation> reservations = new ArrayList<>();

  @ManyToOne
  public TaskList taskList;

  // ...
}

@Entity
public class Reservation extends GenericModel {

  @Id
  private String id = Token.generate(8);

  @ManyToOne
  private Task task;

  // ...
}

例外是:

"CONSTRAINT_INDEX_F ON PUBLIC.TASKLIST_TASK(TASKS_ID)"
Unique index or primary key violation: "CONSTRAINT_INDEX_F ON PUBLIC.TASKLIST_TASK(TASKS_ID)"; SQL statement:
update TaskList_Task set tasks_id=? where TaskList_id=? and position=? [23001-149]

我正在使用JPA 2和Hibernate 3.6.1。我的映射有问题还是Hibernate错误?

更新

这似乎是一个Hibernate问题。具有deleteupdate语句顺序的内容。以下黑客解决了这个问题(部分):

@Entity
public class TaskList extends GenericModel {

  // ....

  public void removeTask(Task task) {
    tasks.remove(task);
    tasks = new ArrayList<>(tasks); // only for Hibernate
    task.taskList = null;
  }
}

Hibernate - clearing a collection with all-delete-orphan and then adding to it causes ConstraintViolationException引导我走向正确的方向。

但是 orphanRemoval=true无法解决我的问题。它导致了下一个异常:“拥有实体实例不再引用具有cascade =”all-delete-orphan“的集合”。所以问题并没有真正解决。

1 个答案:

答案 0 :(得分:1)

您的双向关联映射两次:一次在TaskList中,一次在Task中。 TaskList中的映射注释应为

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="task") 
@OrderColumn(name="position", nullable=false)
public List<Task> tasks = new ArrayList<>();

没有mappedBy属性,Hibernate认为你有两个独立的关联(我怀疑这是你想要的),而不是双向关联。

此外,修改双向关联时,应修改关联的两端。所以removeTask方法应该是

public void removeTask(Task task) {
    tasks.remove(task);
    task.setTaskList(null);
}

这一点尤其重要,因为该关联的拥有方是Task(因为那里没有mappedBy属性。所以这是Hibernate检查必须删除关联的一面。