当前位置: 首页 > 面试题库 >

Spring-Data JPA:保存引用现有实体的新实体

罗渝
2023-03-14
问题内容

问题基本上与下面的问题相同:

JPA级联仍然存在,对分离实体的引用将引发PersistentObjectException。为什么?

我正在创建一个引用现有的分离实体的新实体。现在,当我将此实体保存在spring数据存储库中时,会引发异常:

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist

如果我们查看Spring数据JPA的源代码中的save()方法,则会看到:

public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

如果我们看一下isNew() AbstractEntityInformation

public boolean isNew(T entity) {

    return getId(entity) == null;
}

因此,基本上,如果我保存()一个新实体(id == null),spring数据将始终调用persist,因此此方案将始终失败。

将新项目添加到集合时,这似乎是一个非常典型的用例。

我该如何解决?

编辑1:

注意:

此问题与如何保存在Spring
JPA中引用现有实体的新实体
没有直接关系?。详细地说,假设您收到通过http创建新实体的请求。然后,您从请求中提取信息,并创建您的实体和现有的引用实体。因此,它们将始终处于分离状态。


问题答案:

我想出的最好的是

public final T save(T containable) {
    // if entity containable.getCompound already exists, it
    // must first be reattached to the entity manager or else
    // an exception will occur (issue in Spring Data JPA ->
    // save() method internal calls persists instead of merge)
    if (containable.getId() == null
            && containable.getCompound().getId() != null){
        Compound compound = getCompoundService()
                .getById(containable.getCompound().getId());
        containable.setCompound(compound);   
    }
    containable = getRepository().save(containable);
    return containable; 
}

我们检查是否处于有问题的情况,如果是,只需按ID从数据库重新加载现有实体,然后将新实体的字段设置为该新加载的实例。然后将其附加。

这要求新实体的服务拥有对被引用实体的服务的引用。这应该不是问题,因为无论如何您都在使用spring,因此可以将服务添加为新@Autowired字段。

但是,另一个问题(在我的情况下实际上是需要这种行为)是您在保存新实体时不能同时更改已引用的现有实体。所有这些更改将被忽略。

重要的提示:

在许多情况下(可能是您的情况),这可能会简单得多。您可以将实体管理器的引用添加到您的服务中:

@PersistenceContext
private EntityManager entityManager;

在上面的if(){}块中使用

containable = entityManager.merge(containable);

而不是我的代码(如果可行,请试用)。

在我的情况下,类是抽象的,targetEntity@ManyToOne是抽象的,因此也。直接调用entityManager.merge(containable)会导致异常。但是,如果您的课程都是具体的,则应该可以。



 类似资料:
  • 我有2个实体(我删除了无用的字段): 而且 这似乎符合我的情况(也是我当前的实现),但它不起作用。 我得到以下错误消息: 来自MySQL: 临时解决方案是从存储库中检索所有相应的权限(按permissionName搜索)。那么保存效果很好。逻辑上是正确的,但我希望有一个更简单的程序...

  • 我有两个实体 实体1 实体2 我对Jpa不是很熟悉,所以如果您需要对我的问题进行任何澄清,或者您需要任何更多的信息,请告诉我。

  • 我尝试读取ExcelFiles并将数据保存在postgres数据库中。在某些文件中,我会得到以下错误消息: null 在大多数已爬网的数据中,什么都没有发生。当我尝试保存semster对象时会出现错误。Excel文件的结构如下:标题、模块号、语言、学期号

  • Thread[hz._hzinstance_1_dev.partition-operation.thread-3,5,_hzinstance_1_dev]无法进行远程调用:com.hazelcast.collection.impl.collection.operations.CollectionAddOperation{serviceName='hz:impl:setService',identi

  • 问题内容: 我将SpringJPARepository与hibernate一起使用,并且对实体更新有一个问题。我通过传递单个实体来调用jparepository.save(entity),但在跟踪日志中,我也可以看到针对数据库中其他行发出的更新语句。在调用save之前,我有一个findAll并且某些实体的值正在更改。但是我只传递了一个要保存的实体,但是仍然保存了所有更新的实体。您能提供有关此信息吗