无法使用休眠删除将集合作为子项的实体
Posted
技术标签:
【中文标题】无法使用休眠删除将集合作为子项的实体【英文标题】:can not delete the entity which have collection as child with hibernate 【发布时间】:2011-03-29 11:24:53 【问题描述】:注意:
这是一个交叉帖子: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.delTaskById(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()
我现在收到错误,但实际上并没有删除任务。
我已经在映射中设置了级联。例如,对于任务对象中的tasksteps,我设置cascade.type=all,所以我认为当hibernate尝试删除任务时,它也应该删除它的realted taskssteps,当它尝试删除一个taskstep对象时,它会发现“t_step_t_operator”表引用了“t_step”中的id,所以我还在任务类的“step”字段中设置了“cascade=all”。 但似乎发生的事情并不是我想的那样......
有什么问题?我要疯了!
谁能帮我一个忙?
BWT,级联是什么意思?
例如: 在 TaskStep 类中,我有一个运算符列表;
//Class:TaskStep.
@ManyToMany(
cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
public List<Operator> getOperator()
return operator;
在上面的例子中,我设置了cascade = all,这是否意味着无论对TaskStep进行什么操作(curd),它都会对Opeartors进行相同的操作?
【问题讨论】:
【参考方案1】:如果你想(模拟)一个没有连接表的双向关系,你必须通过创建两个单向关系来做到这一点,并通知 Hibernate 它们之间的关系——正如 JB Nizet 所说,通过使用 mappedBy,但同时保留另一个(@ManyToOne) 映射
@JoinColumn 可以使用,例如,如果您只想映射关系的 @OneToMay 侧但仍然不想要连接表 - 您将指出其他表中应该使用的列,通常是单向引用不影响引用的表,而是使用连接表。在这种情况下你可能不需要@JoinColumn,因为默认情况下 PK (id) 用于双向关系中的 FK 约束(t_taskstep.task_id 列将对 t_task.id 具有 FK 约束)
Cascade 属性将导致对拥有实体的创建/删除操作(更新由 EntityManager/Session 隐式处理)级联到(在您的情况下)集合中的所有实体。因此,对 Task 执行删除操作也会导致删除步骤集合中的所有 TaskSteps 实例,并且还会删除 TaskStep 中的 Operator 运算符。勇敢,但可能会失败,因为您涉及 @ManyToMany 关系 - 其他 TaskStep 实例可能会引用您的删除级联到的 Operator。通常只级联保存更新(或在组件/嵌入式映射关系)并手动处理删除。如果您确定您的集合是唯一一个引用另一个实体的集合,您可以使用 ALL 和 DELETE-ORPHAN,因此只需从集合中删除引用的实体即可删除它们。
@IndexColumn 用于如果您希望记住 List 中对象的顺序。如果您不在乎,请跳过它,您的关系将具有 Bag 语义(无序,允许重复)。通常您不希望在 Collection 中看到重复项,因此应该使用 Set Collection。
回答有点长,抱歉。也许应该简单地提供代码。
【讨论】:
我测试过,如果我只是在映射中使用mappedBy,是不会设置位置的。所以我必须定义两次“joinColumn”,看看这个:opensource.atlassian.com/projects/hibernate/browse/HHH-4390。顺便说一句,从您的友好回答中,我对双向关系和双向引用感到困惑。在我的例子中,任务和任务步骤都持有一个引用,这是双向引用,但是这个适合的关系是什么? bi 还是 un?【参考方案2】:Task 和 TaskStep 之间的关系映射了两次:一次在 Task 中,一次在 TaskStep 中。 Task 中的@JoinColumn 应该消失,@OneToMany 应该有一个“mappedBy”属性:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "task")
@LazyCollection(LazyCollectionOption.FALSE)
@IndexColumn(name = "position")
public List<TaskStep> getSteps()
return steps;
【讨论】:
是的,你是对的,但是如果我只设置一次关系,taskstep中的位置列就不能正常工作,所以我设置了两次。(一个任务的tasksteps的顺序是在我的应用程序中需要。您能告诉我有关级联的信息吗?我无法删除任务。 我怀疑在添加 mappedBy 时位置管理无法正常工作,因为在向任务添加步骤时忘记初始化反向关系。您有责任确保双方都进行了修改。见***.com/questions/5460573/…。关系应始终映射一次,而不是两次。 感谢您的关注。在我的任务中,当我添加一个任务步骤时,我将更新任务步骤的引用任务,就像:“public void addSteps(TaskStep ts) steps.add(ts); ts.setTask(this); ” 所以,我想我已经开始了这种关系。顺便说一句,这是我无法删除任务对象的原因吗?从昨天开始,当我没有在taskStep中添加“indexColum”时,我也无法删除它。以上是关于无法使用休眠删除将集合作为子项的实体的主要内容,如果未能解决你的问题,请参考以下文章
休眠延迟加载不适用于 Spring Boot => 无法延迟初始化角色集合无法初始化代理 - 无会话