我开始在Netbeans中使用带有Glassfish服务器+ Derby数据库的JPA,我对它的行为有些怀疑。我做了以下实验:我使用属性
定义了一个实体“User”@OneToMany(cascade=ALL, mappedBy="user")
public List<Thing> getThings() {
return things;
}
和具有属性
的实体“Thing”@ManyToOne
public Cook4User getUser() {
return user;
}
然后我坚持一个用户并为其添加了一个“Thing”。一切都好,我可以看到两个表“User”和“Thing”,每个表有一个条目,第二个表有一个指示用户ID的外键。 然后我从“Thing”表中删除了元素,运行了一个select语句来恢复用户,在它上面调用了getThings()方法并且......我仍然找到了我从Thing表中删除的元素!这怎么可能?它存放在哪里?我无法在DB中看到它!谢谢你清理我的事情。
编辑:我试图找出产生问题的代码行。
@PersistenceContext
private EntityManager em;
User user = new User();
em.persist(user);
Thing thing = new Thing();
em.persist(thing);
user.getThings().add(thing);
em.remove(thing);
user = em.find(User.class, userid);
logger.log(Level.INFO, "user still contains {0} things", user.getThings().size());
\\thing is still there!
答案 0 :(得分:1)
以SpringRunner和Hibernate作为JPA实现的JUnit测试形式:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-context.xml")
public class TestThings {
private final Logger log = LoggerFactory.getLogger(TestThings.class);
@PersistenceContext
private EntityManager em;
@Test
@Transactional
public void does_not_remove_thing() {
Cook4User user = new Cook4User();
em.persist(user);
Thing thing = new Thing();
em.persist(thing);
user.getThings().add(thing);
user = em.find(Cook4User.class, user.getId());
user.getThings().forEach((t) -> log.info("1 >> Users thing: {}", t.getId()));
em.remove(thing);
em.flush();
user = em.find(Cook4User.class, user.getId());
user.getThings().forEach((t) -> log.info("2 >> Users thing: {}", t.getId()));
assertThat(user.getThings()).isEmpty();
}
@Test
@Transactional
public void removes_thing_when_removed_from_owning_side() {
Cook4User user = new Cook4User();
em.persist(user);
Thing thing = new Thing();
em.persist(thing);
user.getThings().add(thing);
user = em.find(Cook4User.class, user.getId());
user.getThings().forEach((t) -> log.info("1 >> Users thing: {}", t.getId()));
user.getThings().remove(thing);
user = em.find(Cook4User.class, user.getId());
user.getThings().forEach((t) -> log.info("2 >> Users thing: {}", t.getId()));
assertThat(user.getThings()).isEmpty();
}
}
第一个测试does_not_remove_thing
是根据您的问题而失败的,因为您经历过,这是hibernate.show_sql
日志记录设置为true的测试的输出:
Hibernate:
insert
into
Cook4User
(id)
values
(null)
Hibernate:
insert
into
Thing
(id, user_id)
values
(null, ?)
[main] INFO TestThings - 1 >> Users thing: 1
[main] INFO TestThings - 2 >> Users thing: 1
java.lang.AssertionError: expecting empty but was:<[x.Thing@276]>
第二个测试removes_thing_when_removed_from_owning_side
传递输出:
Hibernate:
insert
into
Cook4User
(id)
values
(null)
Hibernate:
insert
into
Thing
(id, user_id)
values
(null, ?)
[main] INFO TestThings - 1 >> Users thing: 1
所以看起来将你的Thing
从关系的所有方面移除(他是)是可行的方法。
虽然,我必须诚实,但我不确定为什么这样做有效,而你的方式则不然。我会理解你是否从一个独立的实体中移除了Thing
但事实并非如此。此外,我在delete
为某个地方em.remove(thing)
致电Thing
后仍然期待em.flush()
查询,但没有(我添加了{{1}}来尝试强制执行此操作)。
也许其他人可以对这里正在发生的事情的更精细的机制有所了解?