当前位置: 首页 > 知识库问答 >
问题:

EntityNotFoundException:已删除的实体传递给EntityM上的持久化anager.remove

仲孙信瑞
2023-03-14

我有ContactEntity(父)和PhoneNumberComponent(子)关系。当我试图成为一名管理者时。删除孩子我得到下面的例外。

此外,我注意到,如果我删除级联类型。保持或更改类型。渴望在AbstractContactEntity中的电话号码映射中偷懒,我的JUnit通过了。

有人能告诉我我错过了什么吗?

使用:hibernate、hsqldb

javax.persistence.EntityNotFoundException: deleted entity passed to persist: [com.bb.sc.contact.jpa.entity.PhoneNumberComponent#<null>]
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1329)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1280)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1286)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:969)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
    at $Proxy35.flush(Unknown Source)
    at test.bb.sc.contact.jpa.entity.PhoneNumberComponentJUnit.testCRUD(PhoneNumberComponentJUnit.java:98)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
@Entity
@Table (name="CONTACT")
@Inheritance (strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn (name="CONTACT_DISCRIMANATOR")
public abstract class AbstractContactEntity implements Auditable {
    @Column (name="CONTACT_ID", nullable=false)
    @Id @GeneratedValue (strategy=GenerationType.IDENTITY)
    private Long id;
    @OneToMany (mappedBy="contact", cascade=CascadeType.ALL, fetch=FetchType.LAZY, targetEntity=PostalAddressComponent.class)
    private Collection<PostalAddressComponent> postalAddresses;
    @OneToMany (mappedBy="contact", targetEntity=PhoneNumberComponent.class, cascade={CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.PERSIST}, fetch=FetchType.EAGER)
    private Collection<PhoneNumberComponent> phoneNumbers;
    @OneToMany (mappedBy="contact", cascade=CascadeType.ALL, fetch=FetchType.LAZY, targetEntity=EmailAddressComponent.class)
    private Collection<EmailAddressComponent> emailAddresses;
    @Embedded
    private DbAudit dbAudit;
@MappedSuperclass
public abstract class AbstractContactDetail implements Auditable{
    @Id @GeneratedValue (strategy=GenerationType.IDENTITY)
    private Long id;
    @OneToOne @JoinColumn (name="CONTACT_TYPE_ID", nullable=false)
    private ContactDetailTypeEntity type;
    @ManyToOne (targetEntity=AbstractContactEntity.class) @JoinColumn (name="CONTACT_ID", nullable=false)
    private AbstractContactEntity contact;
    @Embedded
    private DbAudit dbAudit;
@Entity
@Table (name="PHONE_NUMBER")
@AttributeOverride (name="id", column=@Column(name="PHONE_NUMBER_ID"))
public class PhoneNumberComponent extends AbstractContactDetail {

    @Column (name="AREA_CODE", nullable=false)
    private Integer areaCode;
    @Column (name="PREFIX", nullable=false)
    private Integer prefix;
    @Column (name="SUFFIX", nullable=false)
    private Integer suffix;
    @Column (name="EXTENSION")
    private Integer ext;
@Before
public void setup () {
    contact = new ContactPersonEntity();
    type = new ContactDetailTypeEntity();

    type.setCode("CODE");
    type.setType("TYPE");
    em.persist(contact);
    em.persist(type);
    em.flush();

    // Before each test, make sure the EntityManager has a clean persistence context.
    em.clear();
}   
@Test
public void testDelete () {
    PhoneNumberComponent p = new PhoneNumberComponent(111, 222, 3333, 44, contact, type);
    em.persist(p);
    em.flush();
    assertNotNull (p.getId());

    em.clear();
    PhoneNumberComponent found = em.find(PhoneNumberComponent.class, p.getId());
    assertNotNull (found);
    em.remove(found);
    em.flush();
}

您在我的JUnit中看到的最后em.flush上的JUnit炸弹。另一个观察是,如果我用下面的代码替换JUnit中的em.remove行,测试就会通过。但是,我不希望加载父对象图、遍历它并显式断开父子链接只是为了删除一条记录。谢谢。

    AbstractContactEntity c = em.find(AbstractContactEntity.class, 1L);
    c.getPhoneNumbers();
    Iterator<PhoneNumberComponent> it = c.getPhoneNumbers().iterator();
    while (it.hasNext()) {
        PhoneNumberComponent p = it.next();
        em.remove(p);
        it.remove();
    }

共有2个答案

孔飞翔
2023-03-14

ContactEntity(父级)和PhoneNumberComponent(子级)

您在ContactEntity中拥有PhoneNumberComponent列表。要删除子级,请按照以下步骤操作:

  1. 从数据库中获取PhoneNumberComponent
  2. 从数据库中获取相应的ContactEntity
  3. 从ContactEntity列表中删除相应的PhoneNumber组件
  4. 现在删除PhoneNumberComponent
纪成礼
2023-03-14

在一个可获取的类型中。在持久性上下文中加载子对象也会加载父对象。在少年时代,我执行了一个实体管理器。在找到孩子之前先离开。认为孩子是持久性环境中的唯一实体是一个糟糕的假设。

在调试中,我执行

PhoneNumberComponent found = em.find(PhoneNumberComponent.class, p.getId());

注意到它生成了一对SQL。

Hibernate: select phonenumbe0_.PHONE_NUMBER_ID as PHONE1_3_2_, phonenumbe0_.CONTACT_ID as CONTACT10_3_2_, phonenumbe0_.CREATE_TIMESTAMP as CREATE2_3_2_, phonenumbe0_.CREATE_USER as CREATE3_3_2_, phonenumbe0_.UPDATE_TIMESTAMP as UPDATE4_3_2_, phonenumbe0_.UPDATE_USER as UPDATE5_3_2_, phonenumbe0_.CONTACT_DETAIL_TYPE_ID as CONTACT11_3_2_, phonenumbe0_.AREA_CODE as AREA6_3_2_, phonenumbe0_.EXTENSION as EXTENSION3_2_, phonenumbe0_.PREFIX as PREFIX3_2_, phonenumbe0_.SUFFIX as SUFFIX3_2_, abstractco1_.CONTACT_ID as CONTACT2_0_0_, abstractco1_.CREATE_TIMESTAMP as CREATE3_0_0_, abstractco1_.CREATE_USER as CREATE4_0_0_, abstractco1_.UPDATE_TIMESTAMP as UPDATE5_0_0_, abstractco1_.UPDATE_USER as UPDATE6_0_0_, abstractco1_.ORGANIZATION_NAME as ORGANIZA7_0_0_, abstractco1_.FRIST_NAME as FRIST8_0_0_, abstractco1_.LAST_NAME as LAST9_0_0_, abstractco1_.CONTACT_DISCRIMANATOR as CONTACT1_0_0_, contactdet2_.CONTACT_DETIAL_TYPE_ID as CONTACT1_1_1_, contactdet2_.CODE as CODE1_1_, contactdet2_.DESCRIPTION as DESCRIPT3_1_1_, contactdet2_.TYPE as TYPE1_1_ from PHONE_NUMBER phonenumbe0_ inner join CONTACT abstractco1_ on phonenumbe0_.CONTACT_ID=abstractco1_.CONTACT_ID inner join CONTACT_TYPE contactdet2_ on phonenumbe0_.CONTACT_DETAIL_TYPE_ID=contactdet2_.CONTACT_DETIAL_TYPE_ID where phonenumbe0_.PHONE_NUMBER_ID=?
Hibernate: select phonenumbe0_.CONTACT_ID as CONTACT10_0_2_, phonenumbe0_.PHONE_NUMBER_ID as PHONE1_2_, phonenumbe0_.PHONE_NUMBER_ID as PHONE1_3_1_, phonenumbe0_.CONTACT_ID as CONTACT10_3_1_, phonenumbe0_.CREATE_TIMESTAMP as CREATE2_3_1_, phonenumbe0_.CREATE_USER as CREATE3_3_1_, phonenumbe0_.UPDATE_TIMESTAMP as UPDATE4_3_1_, phonenumbe0_.UPDATE_USER as UPDATE5_3_1_, phonenumbe0_.CONTACT_DETAIL_TYPE_ID as CONTACT11_3_1_, phonenumbe0_.AREA_CODE as AREA6_3_1_, phonenumbe0_.EXTENSION as EXTENSION3_1_, phonenumbe0_.PREFIX as PREFIX3_1_, phonenumbe0_.SUFFIX as SUFFIX3_1_, contactdet1_.CONTACT_DETIAL_TYPE_ID as CONTACT1_1_0_, contactdet1_.CODE as CODE1_0_, contactdet1_.DESCRIPTION as DESCRIPT3_1_0_, contactdet1_.TYPE as TYPE1_0_ from PHONE_NUMBER phonenumbe0_ inner join CONTACT_TYPE contactdet1_ on phonenumbe0_.CONTACT_DETAIL_TYPE_ID=contactdet1_.CONTACT_DETIAL_TYPE_ID where phonenumbe0_.CONTACT_ID=?

然后我添加了下面的一行,并注意到控制台中没有SQL。不需要DB操作,因为EntityManager能够在持久性上下文中找到父对象。

AbstractContactEntity c = em.find(AbstractContactEntity.class, 1L);

如果我将AbstractContactEntity中的phoneNumbers映射更改为FetchType。懒惰我只得到第一SQL。

我不知道为什么Hibernate会这样做,但现在我只是接受行为并进行相应的设计。

下面是Hibernate中可能发生的事情的一个例子。

当我找到()我的子实体时,父实体也会加载到持久性上下文中。然后,remove()将删除指令标记为子指令,将更新指令标记为父指令。最后,当我flush()时,子对象被删除,父对象被推回数据库。但由于该父级仍然有一个对已删除子级的引用,我被EntityNotFoundException踢了一脚:已删除的实体被传递到persist。

 类似资料:
  • 我尝试删除表中的一行: 我的页面: 我现在不知道为什么我会有这个错误。之前我确实删除了一个类似的实体,所有的工作。

  • 问题内容: 我有这种实体: 文件| n ..至..1 | DocumentType | 1 ..至.. n | PropertyType | 1 ..至.. n | 文件属性 我只是尝试删除一个文档,例如:entityManager.remove(document); 但触发错误: 16:45:51,499错误[[Seam Resource Servlet]] Servlet的Servlet.se

  • 问题内容: 我已经成功用hibernate写了我的第一个主要的孩子例子。几天后,我再次使用它并升级了一些库。不知道我做了什么,但是我再也无法使它运行了。有人可以帮助我找出返回以下错误消息的代码中的错误吗: hibernate映射: 编辑: InvoiceManager.java 发票.java InvoiceItem.java 编辑: 从客户端发送的JSON对象: 编辑: 一些详细信息: 我试图通

  • 这个网站上没有一个类似的问题能够解决我的问题。 错误:org.hibernate.persistentobjectexception:传递给persist:healthcheckapi.model.checks的分离实体 示例JSON健康对象: 请注意,这两个对象的ID都是自动生成的,我认为这是问题的一部分。

  • 我有一段运行时间很长的JPA+Hibernate代码,它试图在一个循环中将大量记录插入到DB中。 更奇怪的是,我可以用下面的代码在一次迭代中重现错误。“分离的实体...”第二次刷新时引发错误。那么这是否意味着第一次同花顺是没有操作的呢?

  • 我有一个实体,它已经持久化,并希望将其添加到新生成的父实体(尚未持久化)。如果我尝试持久化父级,我会得到错误“分离的实体传递到持久化:model.child”。我想我必须以某种方式为孩子调用“EntityManager.merge()”,而不是“EntityManager.persisted()”。但是我没有显式调用persisted。这由“cascade=cascadetype.all”注释处理