【发布时间】:2011-10-31 10:21:49
【问题描述】:
我在 Spring 驱动的应用程序中有 2 个 Hibernate 类,如下所示:
@Entity
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToMany(mappedBy = "picture", fetch = FetchType.LAZY)
private Set<InspectionObjectDetail> inspectionObjectDetails = new HashSet<InspectionObjectDetail>();
@Override
public int hashCode() {
// Eclipse generated hashCode()
}
@Override
public boolean equals(Object obj) {
// Eclipse generated equals()
}
}
和
@Entity
public class InspectionObjectDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToMany (fetch = FetchType.LAZY)
@JoinTable(
name = "MXInspectionObjectDetail_picture",
joinColumns = {@JoinColumn(name = "INSPECTIONOBJECTDETAIL_ID")},
inverseJoinColumns = {@JoinColumn(name = "PICTURE_ID")}
)
@Where(clause = "active = true")
private Set<UOCImage> picture = new HashSet<UOCImage>();
@Override
public int hashCode() {
// Eclipse generated hashCode()
}
@Override
public boolean equals(Object obj) {
// Eclipse generated equals()
}
}
我可以向这个关系添加元素并很好地查询它们,但是我尝试删除关系而不实际删除这些对象之一的 jUnit 测试失败。
我目前正在做的是在事务上下文中取消每个对象与另一个对象的链接:
// Junit 测试
@Test
public void deleteInspectionObjectDetailImage() {
InspectionObjectDetail inspectionObjectDetail = new InspectionObjectDetail();
dao.save(inspectionObjectDetail);
someClass.saveInspectionObjectDetailImage(controlObject.getId());
//passes
assertTrue(inspectionObjectDetail.getPictures().size() == 1);
UOCImage image = inspectionObjectDetail.getPictures().iterator().next();
someClass.deleteImage(image);
Set<UOCImage> images = inspectionObjectDetail.getPictures();
//fails
assertTrue(images.size() == 0);
}
// BO类
@Transactional
@Component
public class SomeClass() {
public void delteImage(Image image) {
if(image!= null) {
image.setActive(false);
while(image.getInspectionObjectDetails().iterator().hasNext()) {
InspectionObjectDetail inspectionObjectDetail = image.getInspectionObjectDetails().iterator().next();
inspectionObjectDetail.getPictures().remove(image);
image.getInspectionObjectDetails().remove(inspectionObjectDetail);
}
}
sessionFactory.getCurrentSession().flush();
}
}
Hibernate 日志告诉我,它对关系的插入已正确执行,但我的删除语句没有出现(即使在 session.flush() 之后)。 如果可能的话,我希望保持惰性获取方式不变,因为我希望任一表上的大量读取都不需要加载相应的其他类。
有人指点我吗?
更新
关于 @Thor84no 的建议,我尝试通过 iterator.remove() 函数删除每个关联,因此我的 BO 对象现在看起来像这样:
// BO类
@Transactional
@Component
public class SomeClass() {
public void delteImage(Image image) {
if(image!= null) {
image.setActive(false);
Iterator<InspectionObjectDetail> inspectionObjectDetailsIterator = image.getInspectionObjectDetails().iterator();
while (inspectionObjectDetailsIterator.hasNext()) {
InspectionObjectDetail inspectionObjectDetail = inspectionObjectDetailsIterator.next();
Iterator<UOCImage> imageIterator = inspectionObjectDetail.getPictures().iterator();
while (imageIterator.hasNext()) {
if (imageIterator.next() == image) {
imageIterator.remove();
}
}
inspectionObjectDetailsIterator.remove();
}
}
sessionFactory.getCurrentSession().flush();
}
}
在我的(编辑过的)Junittest 中:
// ...
someClass.deleteImage(image.getId());
assertTrue(image.getInspectionObjectDetails().size() == 0);
assertTrue(inspectionObjectDetail.getPictures().size() == 0);
第一个断言成功,第二个断言失败,所以之间的双向关联
Image InspectionObjectDetail 仅简化为 Image InspectionObjectDetail
【问题讨论】:
-
someMethodToDelete是在deleteInspectionObjectDetailImage中称为deleteImage的方法,我假设不是直接的,那么它们有什么关系?为什么要在此方法中创建和填充新的 ArrayList,而不是在要从中删除内容的现有 List 上使用迭代器?controlObject是什么?它是如何填充的? -
@Thor84no ,感谢您的反馈 - 虽然试图使示例简短易懂,但我把它搞砸了 - (以前命名的) someMethodToDelete 方法是 deleteImage 方法。另外,感谢重复 ArrayList 上的指针,我使用副本来避免并发修改异常,但这是错误的方法。我对其进行了重构以使用迭代器(请参阅编辑),但原来的问题仍然是一样的
-
好的。这说明了一点。但是,您当前的代码可能会导致您所指的
ConcurrentModificationException。使用迭代器时,将其存储为 while 外部的变量(或使用 for 循环)并在迭代器本身上使用remove()方法来删除使用next()返回的最后一个对象。除此之外,在我有机会对其进行测试之前,我不明白为什么它不会被删除。 -
您在
deleteInspectionObjectDetailImage中的deleteImage调用传入image.getId(),但您在SomeClass中的deleteImage方法将图像作为参数。你是如何获得 Image 实例的? -
哎呀,这是简单示例中的另一个错误,而不是实际代码中的错误。很抱歉造成不必要的麻烦,我正在传递
SomeClass中收到的Image实例。
标签: java hibernate hibernate-mapping