是什么导致了带有消息 "detached entity passed to perist" 的 PersistenceException
What caused the PersistenceException with the message "detached entity passed to perist"
我正在使用:
- 带 JPA 的 Quarkus (javax)
- Postgres 11 数据库
我有:
实体
@Entity
@Table(name = "MyEntityTable")
@NamedQuery(name = MyEntity.DOES_EXIST, query = "SELECT x FROM MyEntity x WHERE x.type = :type")
public class MyEntity {
public static final String DOES_EXIST = "MyEntity.DoesExists";
@Id
@SequenceGenerator(name = "myEntitySequence", allocationSize = 1)
@GeneratedValue(generator = myEntitySequence)
private long id;
@Column(name = type)
private String type;
}
存储库
@ApplicationScoped
@Transactional(Transactional.TxType.Supports)
public class MyEntityReporitory {
@Inject
EntityManager entityManager;
@Transactional(Transactional.TxType.Required)
public void persist(final MyEntity entity) {
entityManager.persist(entiy);
}
public boolean doesExist(final String type) {
final TypedQuery<MyEntity> query = entityManager
.createNamedQuery(MyEntity.DOES_EXIST, MyEntity.class)
.setParameter("type", type);
return query.getResultList().size() > 0;
}
}
具有两种变体的测试
变体 1
@QuarkusTest
@QuarkusTestResource(DatabaseResource.class) // used to set up a docker container with postgres db
public class MyEntityRepositoryTest {
private static final MyEntity ENTITY = entity();
@Inject
MyEntityRepository subject;
@Test
public void testDoesExist() {
subject.persist(ENTITY);
final boolean actual = subject.doesExist("type");
assertTrue(actual);
}
@Test
public void testDoesExist_notMatching() {
subject.persist(ENTITY);
final boolean actual = subject.doesExist("another_type");
assertFalse(actual);
}
private static MyEntity entity() {
final MyEntity result = new MyEntity();
result.setType("type")
return result;
}
}
当我执行此测试时 class(两个测试)我在第二次调用 persist
方法时遇到以下异常:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist com.mypackage.MyEntity
...
变体 2
我从测试 class 中删除了常量 ENTITY
,现在我在测试中调用 entity()
方法,例如:
...
subject.persist(entity());
...
在两个地方。现在异常消失了,一切都很好。
问题
谁能给我解释一下,为什么会这样(为什么变体 2 有效而变体 1 无效)?
https://vladmihalcea.com/jpa-persist-and-merge/
The persist operation must be used only for new entities. From JPA perspective, an entity is new when it has never been associated with a database row, meaning that there is no table record in the database to match the entity in question.
testDoesExist
执行,ENTITY
保存到数据库并且 ENTITY.id
设置为 1
testDoesExist_notMatching
执行并持续调用 ENTITY
显示错误,因为它存在于数据库中,它有一个 id
分配
最简单的解决方法是调用 entity()
两次,就像变体 2 一样。
但不要忘记,测试 运行 后记录将存在,并且可能会影响您的其他测试用例。您可能需要考虑在 @After
方法中清理数据,或者如果您打算在多个测试用例中使用此实体,则将 perist 代码放入 @BeforeClass
方法中。
我正在使用:
- 带 JPA 的 Quarkus (javax)
- Postgres 11 数据库
我有:
实体
@Entity
@Table(name = "MyEntityTable")
@NamedQuery(name = MyEntity.DOES_EXIST, query = "SELECT x FROM MyEntity x WHERE x.type = :type")
public class MyEntity {
public static final String DOES_EXIST = "MyEntity.DoesExists";
@Id
@SequenceGenerator(name = "myEntitySequence", allocationSize = 1)
@GeneratedValue(generator = myEntitySequence)
private long id;
@Column(name = type)
private String type;
}
存储库
@ApplicationScoped
@Transactional(Transactional.TxType.Supports)
public class MyEntityReporitory {
@Inject
EntityManager entityManager;
@Transactional(Transactional.TxType.Required)
public void persist(final MyEntity entity) {
entityManager.persist(entiy);
}
public boolean doesExist(final String type) {
final TypedQuery<MyEntity> query = entityManager
.createNamedQuery(MyEntity.DOES_EXIST, MyEntity.class)
.setParameter("type", type);
return query.getResultList().size() > 0;
}
}
具有两种变体的测试
变体 1
@QuarkusTest
@QuarkusTestResource(DatabaseResource.class) // used to set up a docker container with postgres db
public class MyEntityRepositoryTest {
private static final MyEntity ENTITY = entity();
@Inject
MyEntityRepository subject;
@Test
public void testDoesExist() {
subject.persist(ENTITY);
final boolean actual = subject.doesExist("type");
assertTrue(actual);
}
@Test
public void testDoesExist_notMatching() {
subject.persist(ENTITY);
final boolean actual = subject.doesExist("another_type");
assertFalse(actual);
}
private static MyEntity entity() {
final MyEntity result = new MyEntity();
result.setType("type")
return result;
}
}
当我执行此测试时 class(两个测试)我在第二次调用 persist
方法时遇到以下异常:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist com.mypackage.MyEntity
...
变体 2
我从测试 class 中删除了常量 ENTITY
,现在我在测试中调用 entity()
方法,例如:
...
subject.persist(entity());
...
在两个地方。现在异常消失了,一切都很好。
问题
谁能给我解释一下,为什么会这样(为什么变体 2 有效而变体 1 无效)?
https://vladmihalcea.com/jpa-persist-and-merge/
The persist operation must be used only for new entities. From JPA perspective, an entity is new when it has never been associated with a database row, meaning that there is no table record in the database to match the entity in question.
testDoesExist
执行,ENTITY
保存到数据库并且ENTITY.id
设置为 1testDoesExist_notMatching
执行并持续调用ENTITY
显示错误,因为它存在于数据库中,它有一个id
分配
最简单的解决方法是调用 entity()
两次,就像变体 2 一样。
但不要忘记,测试 运行 后记录将存在,并且可能会影响您的其他测试用例。您可能需要考虑在 @After
方法中清理数据,或者如果您打算在多个测试用例中使用此实体,则将 perist 代码放入 @BeforeClass
方法中。