有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在Hibernate中删除多个关联而不实际删除对象

在Spring驱动的应用程序中,我有两个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日志告诉我,它确实插入了关系,但关系执行正确,我的remove语句不会出现(即使在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


共 (3) 个答案

  1. # 1 楼答案

    删除关联的经验法则是清除相关Java对象中的集合,然后保存这些对象

    因此,如果类A有一个类B的集合,而类B有一个类A的集合(多对多关系的情况),那么只需清除

    • A班的B班
    • B班的A班

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

    希望这有帮助

  2. # 2 楼答案

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

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

  3. # 3 楼答案

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

    您知道吗,在列表上调用迭代器()会在每次调用它时创建一个新的迭代器?我猜你的问题是(或者至少在其中一个问题上)你处在一个无限循环中。只要image.getInspectionObjectDetails()至少有一个元素,并且image.getInspectionObjectDetails().iterator().next()总是返回相同的(第一个)元素,while就始终为真

    试试这样:

    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只需检查两个操作数是否具有相同的引用,因此这可能会产生false,尽管逻辑上它是相同的实体(相同的业务密钥):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);