我有这张表“区域”:
编号 |姓名 | parent_id
1 |随便| 100000
其中 parent_id 应该是对 id 的自引用,这意味着该行在地理上属于 100000。
但是由于一开始导入的数据是脏的,所以id为100000的行不存在。
因此在给定的实体中:
@Entity("regions")
public class Region {
private int id;
private String name;
private Region parent;
...
@ManyToOne()
@JoinColumn(name = "parent_id")
public Region getParent() {
return parent;
}
public void setParent(Region parent) {
this.parent = parent;
}
}
当我用 hibernate 做一个列表时:
Session session = sessionHandler.getSession(); //gets current session
Transaction tx = session.beginTransaction();
try {
return (List<T>)session.createQuery("FROM regions").list();
}
catch(HibernateException ex) {
ex.printStackTrace();
if (tx!=null) tx.rollback();
throw ex;
}finally {
sessionHandler.close();
}
它会抛出异常:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [whatever.entities.Region#6046193]
表示 id 6046193 的区域不存在。如前所述,我预计会发生这样的事情。
我的问题是,鉴于我无法将 parent_id 列编辑为可为空,是否有一种方法可以处理此异常,以便系统忽略该异常并让程序继续运行?
最佳答案
您可以尝试将多对一关系的获取类型设置为惰性。
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
public Region getParent() {
return parent;
}
...
我想 hibernate 不会在“全选”过程中抛出错误,如果你这样做的话,你可以在第一次调用 getter 时处理错误。
但我不能 100% 确定这是否有效,而且我认为这不是一个很好的解决方案。我真的认为您应该在导入期间/之后清理您的数据。
如果您不清理数据,则必须永远保留代码中问题的解决方法。如果将来有人删除了 fetch = FetchType.LAZY
,因为他们认为这会带来更好的性能怎么办?您的应用程序将以意想不到的方式中断,只是因为您的实体没有正确反射(reflect)数据库中的内容。
您说您不能将 parent_id
设置为 null,因为该列不可为 null。但是如何为丢失的 ID 创建虚拟条目呢?您可以在导入脏数据后、首次启动应用程序之前立即执行此操作。
此外,仅将列更改为可为空(假设您暂时可以这样做)无论如何都行不通。您仍然需要清理数据 - 在这种情况下,当具有引用 ID 的行不存在时,您必须将所有 parent_id
设置为 null。
关于java - 如果外键引用空行而键不可为空,如何不崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34625903/