如何在不实际删除对象的情况下删除Hibernate中的多对多关联

时间:2011-10-31 10:21:49

标签: java hibernate hibernate-mapping

我在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 Class

@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 Log告诉我它对关系的关系执行了插入是否正确执行,但我的remove语句却没有出现(甚至在session.flush()之后)。 如果可能的话,我想保持延迟抓取它的方式,因为我希望在任一个表上有很多读取,不需要加载相应的其他类。

有人为我指点吗?

更新

关于@ Thor84no的建议,我尝试通过iterator.remove()函数删除每个关联,因此我的BO对象现在看起来像这样:

// BO Class

@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&lt; - &gt; InspectionObjectDetail只被缩减为 Image&lt; - InspectionObjectDetail

3 个答案:

答案 0 :(得分:1)

while(image.getInspectionObjectDetails().iterator().hasNext()) {
    InspectionObjectDetail inspectionObjectDetail = image.getInspectionObjectDetails().iterator().next();
    inspectionObjectDetail.getPictures().remove(image);
    image.getInspectionObjectDetails().remove(inspectionObjectDetail);
}

您是否知道在列表上调用iterator()会在每次调用它时创建一个新的Iterator?我想你的问题是(或者至少是它们)你在这里处于一个无限循环中。只要image.getInspectionObjectDetails()至少包含1个元素,而while image.getInspectionObjectDetails().iterator().next()将始终返回相同(第一个)元素,则while将始终为true。

尝试这样的事情:

Iterator<InspectionObjectDetail> it = image.getInspectionObjectDetails().iterator();
while (it.hasNext()
    InspectionObjectDetail detail = it.next();
    detail.getPictures().remove(image);
    it.remove();
}

<强>更新

if (imageIterator.next() == image)

永远不要在java中比较这样的对象;使用equals代替并在您的实体上实现equals / hashCode。 ==将简单地检查两个操作数是否具有相同的引用,因此这可能会产生错误,尽管逻辑上它是相同的实体(相同的业务键):http://leepoint.net/notes-java/data/expressions/22compareobjects.html

之后你可以改写:

Iterator<UOCImage> imageIterator = inspectionObjectDetail.getPictures().iterator();
            while (imageIterator.hasNext()) {
                if (imageIterator.next() == image) {
                    imageIterator.remove();
                }
            }

为:

inspectionObjectDetail.getPictures().remove(image);

答案 1 :(得分:1)

对于有类似问题的任何人,真正的问题是inspectionObjectDetail调用后deleteImage中的图片集仍然包含图像。为了最容易测试是否是这种情况,您可以使用调试器逐步执行代码,并在调用remove方法之前和之后检查Set是否更改或打印出来。

如果发现未删除该对象,请确保检查要从Set中删除的对象的hashCode()equals()方法。该集只能使用hashCode(),但要记住hashCode()equals()应该是一致的,并且无法保证忽略equals()

答案 2 :(得分:0)

删除关联的拇指规则是清除相关Java对象中的集合,然后保存对象。

因此,如果A类有B类集合,而B类有A类集合(多对多关系案例),那么只需清除

的集合。
  • A类B类
  • B类中的A类

并保存A类和B类。关系将被删除,但对象将保留。

希望这有帮助。