在 FetchType.EAGER 映射中,在持久性上下文中加载子级也会加载父级。在我的 JUnit 中,我在找到子项之前执行了 EntityManager.clear。认为孩子是持久性上下文中唯一的实体是一个糟糕的假设。
在调试中,我执行了
PhoneNumberComponent found = em.find(PhoneNumberComponent.class, p.getId());
并注意到一个pair它生成的 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。不需要任何数据库操作,因为 EntityManager 能够在持久性上下文中找到父级。
AbstractContactEntity c = em.find(AbstractContactEntity.class, 1L);
如果我将 AbstractContactEntity 中的phoneNumbers 映射更改为 FetchType.LAZY,我只会得到第一个 SQL。
Edit
我不知道为什么 Hibernate 这样做 https://stackoverflow.com/questions/11065974/why-does-hibernate-load-the-parent-entity-when-finding-a-child-in-fetchtype-eage,但现在我只是接受这种行为并进行相应的设计。
下面是 Hibernate 中可能发生的情况的说明。
当我 find() 我的子实体时,父实体也会加载到持久性上下文中。然后,remove() 向子级标记一条删除指令,向父级标记一条更新指令。最后,当我flush()时,子级被删除,父级被推回数据库。但由于该父级仍然引用已删除的子级,因此我被 EntityNotFoundException: 已删除的实体传递给持久性所困扰。