在OneToMany映射上进行测试时,我花了几个小时才弄清楚这种令人惊讶的行为。我重读了实体d hibernate指南,仔细检查代码,测试desisgn,最终找出可能与hibernate缓存设计有关的根本原因。以下是代码摘录:
@Entity
public class Organization {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long id;
@ManyToOne
@JoinColumn(name="cooperation_id")
private Cooperation cooperation;
@ManyToOne(optional=true)
@JoinColumn(name="organization_id", nullable=true)
private Organization upperLevel;
@OneToMany(mappedBy="upperLevel")
private Collection<Organization> subOrganizations = new ArrayList<Organization>();
@OneToOne(mappedBy="organization")
private TimeoffSetting timeoffSetting;
private String name;
...
JUNIT测试:
@PersistenceContext
private EntityManager entityManager
@Transactional
public void organization() {
Organization organization_it = new Organization(cooperation, "IT");
organization_it.setUpperLevel(organizationTop);
organization_it = organizationRepository.save(organization_it);
Organization organization_hr = new Organization(cooperation, "HR");
organization_hr.setUpperLevel(organizationTop);
organization_hr = organizationRepository.save(organization_hr);
Organization organization_unix = new Organization(cooperation, "UNIX");
organization_unix.setUpperLevel(organization_it);
organization_unix = organizationRepository.save(organization_unix);
boolean hasIt = false;
boolean hasHr = false;
Iterable<Organization> organizations = organizationRepository.findAll();
for(Organization o: organizations) {
entityManager.refresh(o);
if (o.getName() == "cooperation") {
org.junit.Assert.assertTrue(o.isTopLevel());
org.junit.Assert.assertEquals(o.getSubOrganizations().size(), 2);
}
...
请注意这里的entityManager.refresh(o)方法调用,如果我不刷新实体,assertEquals(getSubOrganizations().size(),2)OneToMany映射测试将导致失败。通过谷歌搜索互联网,Spring的集成测试在编写ORM测试时应该更加谨慎。一篇文章可能是有用的春季陷阱交易测试
很简单:您分配了It和HR的upperLevel
组织,但忽略了通过将It和HR添加到顶级的subOrganizations
列表来保持对象图的一致性。
这对Hibernate来说并不是一个真正的问题,因为您负责设置每个双向关联的所有者侧,这就是Hibernate保持这种关联所需要的全部内容。
但是,由于对象不是由Hibernate创建和填充的,而是由您创建和填充,因此它们就是您创建的。正如您在使用refresh()
时注意到的,当Hibernate负责创建和填充实体时,关联的双方是一致的。