有 Java 编程相关的问题?

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

java Hibernate:@OneToMany:从“多”端删除实体会导致EntityNotFoundException

我拥有以下实体:

@Entity
public static class Parent {
    @Id
    @GeneratedValue
    private Long id;

    String st;

    @OneToMany(mappedBy = "parent")
    Set<Child> children = new HashSet<>();
    // get,set 
}

@Entity
public static class Child {


    @Id
    @GeneratedValue
    private Long id;

    String st;

    @ManyToOne()
    private Parent parent;
    //get,set
  }

注意,@OneToMany侧没有级联

我想要的是:

  1. 我有一个父母和一个孩子处于分离状态
  2. 现在我想根据某些条件删除子项,所以我正在访问所有子项,找到必要的子项并直接通过em.remove(child)删除它我将其从家长的收藏中删除
  3. 之后,我想改变一些属性的家长,并保存它也。 我发现EntityNotFound是个例外

我执行了一些调试,发现子集合是PersistentSet,它记住了storedSnapshot中的状态。所以,当我将父对象合并到上下文-Hibernate时,请对存储的快照执行一些操作,并尝试从DB加载子对象。当然,不存在这样的实体,因此会引发异常

因此,我可以做几件事:

  1. 带有@NotFound的映射集合(action=NotFoundAction.IGNORE)
  2. 从子集合中删除期间-强制转换到PersistentSet并将其清除

但这似乎是一个黑客

所以, 1.我做错了什么?看起来,直接删除子实体是正确的
2.有没有更优雅的处理方法

可复制示例:

@Autowired
PrentCrud parentDao;

@Autowired
ChiildCrud childDao;
@PostConstruct
public void doSomething() {

    LogManager.getLogger("org.hibernate.SQL").setLevel(Level.DEBUG);


    Parent p = new Parent();
    p.setSt("1");
    Child e = new Child();
    e.setParent(p);
    e.setSt("c");
    p.getChildren().add(e);
    Parent save = parentDao.save(p);
    e.setParent(save);
    childDao.save(e);
    Parent next = parentDao.findAll().iterator().next();
    next.setSt("2");
    next.getChildren().size();
    childDao.deleteAll();
    next.getChildren().clear();
    if (next.getChildren() instanceof PersistentSet) { // this is hack, not working without
        ((Map)((PersistentSet) next.getChildren()).getStoredSnapshot()).clear();
    }
    parentDao.save(next); // exception is thrwn here without hack
    System.out.println("Success");

}

共 (2) 个答案

  1. # 1 楼答案

    您是否尝试过将fetch type更改为eager?关系违约 OneToMany: LAZY ManyToOne: EAGER ManyToMany: LAZY OneToOne: EAGER

    可能是因为fetch方法而缓存了它

  2. # 2 楼答案

    你可以用next.setChildren(new HashSet<>());代替next.getChildren().clear();来摆脱getStoredSnapshot()).clear()

    但是,使用级联和删除将更加优雅

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    Set<Child> children = new HashSet<>();
    
    public void doSomething() {
        ...
        next.setSt("2");
        next.setChildren(new HashSet<>());
        parentDao.save(next);
        System.out.println("Success");
    }