20

我们正在使用 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
What I Want is 而不是异常,如果关联不存在,则将此字段设置为 NULL。

我尝试了几种不同的方法,例如在关系注释中使用 optional=true (顺便说一句,这是默认选项),将其设置为 Nullable 等。似乎没有什么能解决问题,似乎所有这些选项都被忽略了。

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

你们中有人知道解决这个问题的其他方法吗?

非常感谢您的帮助!

4

6 回答 6

7

以下是此问题的替代解决方案。我不得不建立在一个关系有时会损坏的旧数据库之上。这就是我仅使用 JPA 解决它的方法。

@PostLoad
public void postLoad(){
    try {
        if(getObject() != null && getObject().getId() == 0){
            setObject(null);
        }
    }
    catch (EntityNotFoundException e){
        setObject(null);
    }
} 
于 2013-10-23T13:42:56.533 回答
2

尝试将参数添加optional = true到您的@OneToOne注释中。

于 2012-09-04T17:35:26.357 回答
2

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

  1. 您的 Second 类的实例被删除,而 First 类的实例对此一无所知。
  2. 您需要一种方法让 First 的实例知道它的 Second 实例何时被删除。
  3. 用于删除的级联选项在这里没有帮助。
  4. 当 First 的实例存在于 Second 的实例中时,您可以尝试使用双向关系。它允许您在删除第二个之前通过第二个实例更新第一个实例
  5. 双向关系 - 是邪恶的。我想在你的情况下,第一 - 是第二的所有者。不允许任何服务直接删除您的第二个实例。让与 First 实例一起工作的服务删除 Second 实例。在这种情况下,您可以先将“第二”字段设为可空,然后通过 EntityManager 删除 Second 的实例。
  6. 当执行查询并且启用二级缓存并且查询有提示时,您可能会遇到异常,该提示允许缓存其结果。我会通过以下方法为您提供查询结果:
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 而不是通过查询处理实体,并且由于实体被缓存而出现异常,则当您删除 Second 时,您可能会使缓存中 First 的所有实体无效。

我想讨论这个解决方案,因为我无法对其进行测试,也无法使其正常工作。如果有人尝试,请告诉我。

PS:如果有人对休眠进行了单元测试,可以重现此问题,请告诉我。我想进一步调查它。

于 2015-04-17T08:45:50.090 回答
2

当您删除关联的实体 ID 时会发生这种情况。就我而言,我有 Product 表,具体取决于 Brand 表。我删除了其中一个产品实例所依赖的品牌 ID 的行或实体。

于 2018-05-06T09:54:08.280 回答
0

在对应的实体类中添加一个测试怎么样:

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

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

于 2012-09-04T11:33:34.430 回答
-2

尝试cascade=CascadeType.ALL在@OneToMay(******) 中使用。

于 2020-07-07T08:50:54.640 回答