can not delete the entity which have collection as child with hibernate
NOTE:
This is a croass post at:hibernate forum
Since I got no answer ,so I ask here to see if I can get some help. :)
If this is solved here,I will post the answer in the hibernate forum. :)
In my application,I have some entities which own some collections,when I have no idea to delete them.
This is the core codes of my eneity:
Code:
@Entity
@Table(
name = "t_task")
public class Task {
private int id;
private List<TaskStep> steps = new ArrayList<TaskStep>();
public Task() {
this.createTime = new Date();
}
public Task(String name) {
this();
this.name = name;
}
@Id
@GeneratedValue
public int getId() {
return id;
}
@OneToMany(
cascade = CascadeType.ALL)
@JoinColumn(
name = "task_id",
nullable = false)
@LazyCollection(LazyCollectionOption.FALSE)
@IndexColumn(
name = "position")
public List<TaskStep> getSteps() {
return steps;
}
// domain method
public void addSteps(TaskStep ts) {
steps.add(ts);
ts.setTask(this);
}
public void removeStep(TaskStep ts) {
steps.remove(ts);
}
// setter
public void setId(int id) {
this.id = id;
}
public void setSteps(List<TaskStep> steps) {
this.steps = steps;
for (TaskStep st : steps) {
st.setTask(this);
}
}
}
//TaskStep:
@Entity
@Table(
name = "t_taskstep")
public class TaskStep {
private int id;
private List<Operator> operator = new ArrayList<Operator>();
private Task task;
public TaskStep() {}
@Id
@GeneratedValue
public int getId() {
return id;
}
@ManyToMany(
cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
public List<Operator> getOperator() {
return operator;
}
@ManyToOne
@JoinColumn(
name = "task_id",
nullable = false,
updatable = false,
insertable = false)
public Task getTask() {
return task;
}
// domain method start
public void addOperator(Operator op) {
operator.add(op);
}
// setter
public void setId(int id) {
this.id = id;
}
public void setOperator(List<Operator> operator) {
this.operator = operator;
}
public void setTask(Task task) {
this.task = task;
}
}
//Operator:
@Entity
@Table(
name = "t_operator")
public class Operator {
private int id;
private List<TaskStep> steps = new ArrayList<TaskStep>();
public Operator() {}
@Id
@GeneratedValue
public int getId() {
return id;
}
// //setter
public void setId(int id) {
this.id = id;
}
public void setSteps(List<TaskStep> steps) {
this.steps = steps;
}
@ManyToMany(
mappedBy = "operator")
public List<TaskStep> getSteps() {
return steps;
}
}
In the db,there are tables of "t_task","t_operator","t_st开发者_JAVA百科ep","t_step_operator".
I use this manner to remove the task: Code: taskDao.delTaskById(5);
This is the dao:
Code:
public void delTaskById(int id) {
Task t = queryTaskById(id);
Session sess = factory.getCurrentSession();
try {
sess.beginTransaction();
sess.delete(t); // 1)
sess.flush();
sess.getTransaction().commit();
} catch (HibernateException e) {
sess.getTransaction().rollback();
}
}
I got a error which said "can not delete or update a parent row....".
Then I tried use the repalce the
sess.delete(t)
to
sess.createQuery("delete from Task t where t.id="+id).executeUpdate()
I got now error,but the task is not removed actually.
I have set the cascade in the mapping. for example,for the taskstesps in the task object,I set cascade.type=all,so I think when hibernate try to delete the task,it should del its realted tasksteps as well,and when it try to delete a taskstep object, it will find that the "t_step_t_operator" table is referring the id in "t_step",so I also set "cascade=all" for the "step" field in task class. But seems that what is going on is not what I thought....
What is the problem? I am going to crazy!
Any one can do me a favor?
BWT,what does the cascade meaning?
For example: In the TaskStep calss,I have a List of Operators;
//Class:TaskStep.
@ManyToMany(
cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
public List<Operator> getOperator() {
return operator;
}
In the above exmaple,I set cascade = all,does this mean no matter what operation(curd) to the TaskStep,it will do the same operation to the Opeartors?
If you want (to simulate) a bidirectional relation without a join table, you must do this by creating two unidirectional relations and inform Hibernate about the relation between them - by using mappedBy, as JB Nizet says, but also keeping the other (@ManyToOne) mapping
@JoinColumn can be used e.g if you want to only map the @OneToMay side of a relation but still don't want a join table - you'll point out a column in other table that should be used, normally unidirectional references don't affect the referenced table and instead uses join tables. You prob don't need @JoinColumn in this case, since by default PK (id) is used in FK constraints in bidirectional relations (t_taskstep.task_id column will have FK constraint to t_task.id)
Cascade attribute will cause Create/Delete actions (updates are implicitly handled by EntityManager/Session) on owning entities to cascade down to (in your case) all entities in a Collection. So doing a delete on a Task would also lead to delete of all TaskSteps instances in your steps Collection, and also delete the Operator operator in TaskStep. Brave, but likely to fail since you have @ManyToMany relations involved - other TaskStep instances might reference the very Operator your delete is cascaded to. Normally only cascade save-update (or map relation at a Component/Embedded) and handle deletes manually. If you though are sure that your collection is the only one referencing another entity you could use ALL and also DELETE-ORPHAN and thus cause referenced Entities to be deleted simply by removing them from the Collection.
@IndexColumn is used if you want the order of the objects in the List to be remembered. If you don't care, skip it and your relation will have Bag semantics (unordered, duplicated allowed). Often you don't want to see duplicates in a Collection, so the Set Collection should then be used.
Kind of long answer, sorry. Should've simply provided the code perhaps.
Your relationship between Task and TaskStep is mapped twice : once in Task, and once in TaskStep. The @JoinColumn in Task should disappear, and the @OneToMany should have a "mappedBy" attribute:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "task")
@LazyCollection(LazyCollectionOption.FALSE)
@IndexColumn(name = "position")
public List<TaskStep> getSteps() {
return steps;
}
精彩评论