Spring-Data JPA:保存引用现有实体的新实体
问题基本上与下面的问题相同:
JPA级联持久化并且对分离实体的引用会抛出PersistentObjectException。 为什么?
我正在创建一个引用现有的独立实体的新实体。 现在,当我在Spring数据存储库中保存此实体时,会抛出exception:
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist
如果我们看一下spring数据JPA源代码中的save()方法,我们看到:
public S save(S entity) { if (entityInformation.isNew(entity)) { em.persist(entity); return entity; } else { return em.merge(entity); } }
如果我们在AbstractEntityInformation
查看isNew()
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);
而不是我的代码(如果它工作未经测试)。
在我的例子中,类是抽象的,而@ManyToOne
targetEntity
也是抽象的。 直接调用entityManager.merge(可包含)然后会导致exception。 但是,如果你的课程都是具体的,这应该有效。
我有一个类似的问题,我试图用一个已保存的实体对象保存一个新的实体对象。
我所做的是实现了Persistable
public class MyEntity implements Persistable { public boolean isNew() { return null == getId() && subEntity.getId() == null; }
或者您可以使用AbstractPersistable并覆盖那里的isNew。
我不知道这是否会被认为是处理这个问题的好方法,但它对我来说非常好,而且感觉非常自然。
我对@EmbeddedId
和业务数据作为id的一部分存在同样的问题。
知道实体是否是新的唯一方法是执行(em.find(entity)==null)?em.persist(entity):em.merge(entity)
但是spring-data只提供了save()
方法,并且没有办法用find()
方法填充Persistable.isNew()
find()
方法。
- 如何将子域转换为嵌入式Tomcat 8和Spring引导的路径
- Java Arraylist得到了java.lang.IndexOutOfBoundsException?
- Java Thread何时到达’Die’状态
- 从Java批量插入Oracle
- ANTLR4 java解析器可以处理非常大的文件,还是可以流文件
- 使用KeyListener更改字符串背景并在键释放时将其设置回来 键入Tutor计划
- JDBCTemplate使用BeanPropertyRowMapper设置嵌套的POJO
- Memento模式与序列化的区别
- Hibernate使用hibernate.jdbc.batch_versioned_data保存过时数据