1

I have the following entities and get an exception if I try to remove a Task from the TaskList via removeTask method.

@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;

  // ...
}

The exception is:

"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]

I'm using JPA 2 with Hibernate 3.6.1. Is something wrong with my mapping or is it a Hibernate bug?

UPDATE

It seems to be a Hibernate problem. Something with the order of delete and update statements. The following hack solved the problem (partly):

@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 lead my in the right direction.

But orphanRemoval=true doesn't work with my workaround. It leads to the next exception: "A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance". So the problem is not really solved.

Community
  • 1
  • 1
deamon
  • 89,107
  • 111
  • 320
  • 448
  • Great, the hack worked for me! My scenario was the following one: I removed the first element from a list and then I appended the element at the end of the list. – rwitzel Jan 23 '14 at 19:59

1 Answers1

1

Your bidirectional association is mapped twice: once in TaskList, and once in Task. The mapping annotations in TaskList should be

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

Without the mappedBy attribute, Hibernate considers that you have two separate associations (and I doubt that's what you want), rather than a bidirectional one.

Moreover, when you modify a bidirectional association, both sides of the association should be modified. So the removeTask method should be

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

That's particularly important, because the owning side of the association is Task (because that's where ther is no mappedBy attribute). So this is the side that Hibernate inspects to know that the association must be removed.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • `mappedBy` cannot be used together with `@OrderColumn`, because Hibernate consider it to be a bad practice and needs a join table instead. See: http://stackoverflow.com/questions/2956171/ I tried to remove the references as suggested, but it didn't solve the problem. – deamon Jan 08 '12 at 17:04