无法删除具有hibernate作为子集合的实体

时间:2011-03-29 11:24:53

标签: hibernate mapping

注:

这是一个发帖:hibernate forum

由于我没有回答,所以我在这里问我是否可以得到一些帮助。 :)

如果在这里解决了这个问题,我将在hibernate论坛中发布答案。 :)


在我的应用程序中,当我不知道要删除它们时,我有一些拥有某些集合的实体。

这是我的核心代码:

代码:

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

在db中,有“t_task”,“t_operator”,“t_step”,“t_step_operator”等表。

我用这种方式删除任务: 码: taskDao.delTask​​ById(5);

这是道:

代码:

   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();
      }
   }

我收到一条错误,上面写着“无法删除或更新父排......”。

然后我尝试使用repalce

sess.delete(t)

sess.createQuery("delete from Task t where t.id="+id).executeUpdate()

我现在收到错误,但实际上并没有删除任务。

我在映射中设置了级联。例如,对于任务对象中的taskstesps,我设置了cascade.type = all,所以我认为当hibernate尝试删除任务时,它也应该删除它的自己的任务步骤,并且当它尝试删除taskstep对象时,它会发现“t_step_t_operator”表引用了“t_step”中的id,所以我还为任务类中的“step”字段设置了“cascade = all”。 但似乎发生的事情并不是我想的......

有什么问题?我要疯了!

任何人都可以帮我一个忙吗?

BWT,级联是什么意思?

例如:  在TaskStep calss中,我有一个操作符列表;

   //Class:TaskStep.
   @ManyToMany(
         cascade = CascadeType.ALL)
   @LazyCollection(LazyCollectionOption.FALSE)
   public List<Operator> getOperator() {
      return operator;
   }

在上面的例子中,我设置了cascade = all,这是否意味着无论对TaskStep进行什么操作(curd),它都会对Opeartors做同样的操作?

2 个答案:

答案 0 :(得分:2)

如果你想要(模拟)没有连接表的双向关系,你必须通过创建两个单向关系并通知Hibernate关于它们之间的关系 - 通过使用mappedBy,如JB Nizet所说,但也保留另一个(@ManyToOne)映射

可以使用@JoinColumn,例如,如果您只想映射关系的@OneToMay端但仍然不想要连接表 - 您将指出应该使用的其他表中的列,通常是单向引用不影响引用的表,而是使用连接表。在这种情况下,你不需要@JoinColumn,因为默认情况下PK(id)用于双向关系中的FK约束(t_taskstep.task_id列将对t_task.id赋予FK约束)

Cascade属性将导致拥有实体的创建/删除操作(更新由EntityManager / Session隐式处理)以级联到(在您的情况下)Collection中的所有实体。因此,对任务执行删除操作也会导致删除步骤Collection中的所有TaskSteps实例,并删除TaskStep中的Operator运算符。勇敢,但由于涉及@ManyToMany关系可能会失败 - 其他TaskStep实例可能会引用您的删除级联的运算符。通常只有级联保存更新(或组件/嵌入式的映射关系)并手动处理删除。如果您确定您的集合是唯一一个引用另一个实体的集合,那么您可以使用ALL和DELETE-ORPHAN,从而只需将其从集合中删除即可删除引用的实体。

如果要记住列表中对象的顺序,则使用@IndexColumn。如果您不在乎,请跳过它,您的关系将具有Bag语义(无序,允许重复)。通常,您不希望在Collection中看到重复项,因此应该使用Set Collection。

有点长的答案,对不起。应该只是提供代码。

答案 1 :(得分:1)

您在Task和TaskStep之间的关系被映射两次:一次在Task中,一次在TaskStep中。任务中的@JoinColumn应该消失,而@OneToMany应该有一个“mappedBy”属性:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "task")
@LazyCollection(LazyCollectionOption.FALSE)
@IndexColumn(name = "position")
public List<TaskStep> getSteps() {
    return steps;
}