我们正在使用JPA从数据库加载一些东西。某些实体可能在它们之间具有可选关系,例如
@Entity
public class First {
....
@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
@JoinColumns(value = {
JoinColumn(name = "A_ID", referencedColumnName = "A_ID", insertable = false, updatable = false),
JoinColumn(name = "B_ID", referencedColumnName = "B_ID", insertable = false, updatable = false)})
private Second second;
当数据库中存在此关联时,一切正常。如果不是,我会得到javax.persistence.EntityNotFoundException
如果关联不存在,我想要的是将此字段设为NULL而不是异常。
我尝试了几种不同的东西,例如在关系注释中使用optional = true(btw是默认选项),将其设置为Nullable等。似乎没有什么可以做到的,似乎所有这些选项都被忽略了。
我发现很多链接提到了这个相同的问题(以及stackoverflow中的一些问题)但是在所有这些问题中,建议使用Hibernate中的@NotFound
注释。但是我们不想对Hibernate有任何依赖(我们希望保持所有纯粹的JPA)。
你们其中任何人都知道解决这个问题的其他方法吗?
非常感谢你的帮助!
答案 0 :(得分:7)
以下是此问题的替代解决方案。我不得不建立在一个旧数据库的基础上,这个数据库的关系有时会被破坏。这就是我只使用JPA解决它的方法。
@PostLoad
public void postLoad(){
try {
if(getObject() != null && getObject().getId() == 0){
setObject(null);
}
}
catch (EntityNotFoundException e){
setObject(null);
}
}
答案 1 :(得分:2)
我遇到了同样的问题。它并不总是可重复的,所以我无法测试它,但这里有一些想法:
- 第二个类的实例被删除,而First类的实例对此一无所知。
- 当删除其第二个实例时,您需要一种让First知道实例知道的方法。
- 用于删除的级联选项在这里没有用。
- 当Second实例存在于Second实例中时,您可以尝试使用双向关系。它让你更新实例 首先通过第二个实例,然后删除第二个
- 双向关系 - 是邪恶的。在你的情况下,我认为,First - 是Second的所有者。不允许任何服务删除你的 二次直接。让服务与实例一起工作 首先删除Second的实例。在这种情况下,你可以做到 “第二个”字段可以为空,首先是删除第二个实例 EntityManager的。
- 执行查询时可能会出现异常,并且启用了第二级缓存并且查询有提示,这样可以缓存其结果。一世 会通过以下方法为您提供查询结果:
醇>
private List<?> getQueryResult(final Query query)
{
try
{
return query.getResultList();
}
catch (EntityNotFoundException e)
{
return query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH).getResultList();
}
}
- 如果您通过EntityManger处理实体,但不通过查询,并且由于实体被缓存而导致异常,则可能会使所有实体无效 删除第二个时在缓存中的First实体。
醇>
我想讨论这个解决方案,因为我无法测试它,也无法让它变得有效。如果有人试图,请告诉我。
PS:如果有人对hibernate进行了单元测试,那就重现了这个问题,请你告诉我。我希望进一步调查。答案 2 :(得分:2)
删除关联的实体ID时会发生这种情况。在我的情况下,我有产品表取决于品牌表。我删除了一个品牌ID的行或实体,其中一个产品实例依赖于它。
答案 3 :(得分:0)
如何在对应的实体类中添加测试:
public boolean getHasSecond() {
if (this.Second != null) {
return true;
} else {
return false;
}
}
像这样,您可以检查关系是否存在......
答案 4 :(得分:0)
尝试在OneToOne注释上添加optional = true。
答案 5 :(得分:-1)
尝试在@OneToMay(******)中使用cascade=CascadeType.ALL
。