如何使用JPA解决javax.persistence.EntityNotFoundException(而不是使用@NotFound)

我们正在使用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而不是exception。

我尝试了几个不同的东西,例如在关系注释中使用optional = true(btw是默认选项),将它设置为Nullable等等。似乎没有什么可以做的,看起来所有这些选项都被忽略了。

我发现很多链接提到了这个相同的问题(以及stackoverflow中的一些问题)但是在所有这些问题中,建议使用来自Hibernate的@NotFound注释。 但我们不希望对Hibernate有任何依赖(我们希望保持所有纯粹的JPA)。

你们其中任何人都知道解决这个问题吗?

非常感谢您的帮助!

以下是此问题的替代解决方案。 我不得不建立在旧数据库的基础上,其中关系有时会被破坏。 这就是我只使用JPA解决它的方法。

 @PostLoad public void postLoad(){ try { if(getObject() != null && getObject().getId() == 0){ setObject(null); } } catch (EntityNotFoundException e){ setObject(null); } } 

我遇到了同样的问题。 它并不总是可重复的,所以我无法测试它,但这里有一些想法:

  1. 第二个类的实例被删除,而First类的实例对此一无所知。
  2. 当删除其第二个实例时,您需要一种让First知道实例知道的方法。
  3. 用于删除的级联选项在这里没有帮助。
  4. 当First实例存在于Second实例中时,您可以尝试使用双向关系。 它允许您在删除第二个之前通过Second实例更新First的实例
  5. 双向关系 – 是邪恶的。 在你的情况下,我认为,First – 是Second的所有者。 不允许任何服务直接删除您的第二个实例。 让使用First的实例的服务删除Second的实例。 在这种情况下,您可以首先使“第二”字段为空,而不是通过EntityManager删除第二个实例。
  6. 执行查询时可能会出现exception,并且启用了第二级缓存并且查询有提示,这允许缓存其结果。 我会通过以下方法为您提供查询结果:
 private List getQueryResult(final Query query) { try { return query.getResultList(); } catch (EntityNotFoundException e) { return query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH).getResultList(); } } 
  1. 如果您通过EntityManger处理实体,但不通过查询,并且由于实体被缓存而导致exception,则在删除Second时,可能会使First in cache中的所有实体无效。

我想讨论这个解决方案,因为我无法测试它,也无法让它变得有效。 如果有人试图,请告诉我。

PS:如果有人对hibernate进行了unit testing,那就重现了这个问题,请你告诉我。 我想进一步调查。

删除关联的实体ID时会发生这种情况。 在我的情况下,我有产品表取决于品牌表。 我删除了一个品牌ID的行或实体,其中一个产品实例依赖于该行。

如何在对应的实体类中添加测试:

 public boolean getHasSecond() { if (this.Second != null) { return true; } else { return false; } } 

像这样,你可以检查关系是否存在……

尝试在OneToOne批注上添加optional = true。