Spring数据和双向关系的持久性上下文问题

Spring数据和双向关系的持久性上下文问题,spring,hibernate,jpa,spring-data,Spring,Hibernate,Jpa,Spring Data,这个问题在编写测试时出现,但可能也适用于应用程序代码,这给我留下了一些问题 (问题就在底部) 情况摘要: 我正在编写DataJpaTests测试,以测试由一些crudepositories支持的服务层对象。 最初,我使用一些数据为存储库添加种子,然后进行服务调用 最后,我查询存储库以断言状态 我在父母和孩子之间有双向的一对多关系(ren) 子对象将其父对象作为自然Id的一部分 在我的断言中,parent.getChildren().contains(child)失败为false,但它应该为

这个问题在编写测试时出现,但可能也适用于应用程序代码,这给我留下了一些问题

(问题就在底部)

情况摘要:

  • 我正在编写
    DataJpaTests
    测试,以测试由一些
    crudepositories
    支持的服务层对象。
    • 最初,我使用一些数据为存储库添加种子,然后进行服务调用
    • 最后,我查询存储库以断言状态
  • 我在父母和孩子之间有双向的一对多关系(ren)
  • 子对象将其父对象作为自然Id的一部分
  • 在我的断言中,
    parent.getChildren().contains(child)
    失败为
    false
    ,但它应该为true
@测试
公开无效测试(){
//种子
Parent=Parent.builder()
.电邮(“a@b.cbuild();
Child=Child.builder()
.电邮(“x@y.zbuild();
parent.addChild(child);
parentRepository.save(父级);
// ----
//忽略不相关的服务代码
// ----
//断言
parent=parentRepository.findById(parent.getId()).get();
assertTrue(parent.getChildren().contains(child));//失败
}
这让我进行了调试和调查。结果表明,父对象的
子对象
集与之前的
持久集
完全相同。那时我学到了更多关于持久性上下文的知识,尽管这些知识仍然很肤浅

如果我执行以下任一操作,则测试通过:

  • 插入重复的
    parentRepository.save(parent)
  • 自动连接
    EntityManager
    并调用
    refresh(父项)
    flush()、clear()
    组合
  • 我将父母从孩子的自然Id中删除
  • 重新排序
    addChild
    中的操作,以便在插入父对象的子对象集中之前为子对象指定父对象
  • 这是因为
    Child
    的hashcode中有
    parent
    ,并且当最初插入到父对象的子对象集中时,没有指定父对象,因此hashcode是不同的

    为供参考,各实体:

    @实体
    @Getter@Setter@Builder
    @noargsconstuctor@allargsconstuctor
    公共类父类{
    @身份证
    @GeneratedValue(策略=GenerationType.IDENTITY)
    私人长id;
    @归化
    私人字符串电子邮件;
    @OneToMany(mappedBy=“parent”,cascade=CascadeType.ALL,orphan=true)
    @Builder.Default
    private Set children=new HashSet();
    公共无效添加子项(最终子项){
    getChildren().add(child);
    child.setParent(this);
    }
    public void removeChild(最终子级){
    getChildren().remove(子对象);
    setParent(null);
    }
    @凌驾
    公共布尔等于(最终对象o){
    if(this==o){
    返回true;
    }
    如果(o==null | | getClass()!=o.getClass()){
    返回false;
    }
    最终父项=(父项)o;
    返回email.equals(parent.email);
    }
    @凌驾
    公共int hashCode(){
    返回Objects.hash(电子邮件);
    }
    }
    @实体
    @Getter@Setter@Builder
    @noargsconstuctor@allargsconstuctor
    公营儿童{
    @身份证
    @GeneratedValue(策略=GenerationType.IDENTITY)
    私人长id;
    @归化
    私人字符串电子邮件;
    @多通(可选=假)
    @JoinColumn(name=“parent\u identifier”)
    @归化
    私人家长;
    @凌驾
    公共布尔等于(最终对象o){
    if(this==o){
    返回true;
    }
    如果(o==null | | getClass()!=o.getClass()){
    返回false;
    }
    最终子女=(子女)o;
    返回email.equals(child.email)&&
    parent.equals(child.parent);
    }
    @凌驾
    公共int hashCode(){
    返回Objects.hash(电子邮件、父级);
    }
    }
    
  • 如果我没有通过
    EntityManager
    手动执行,
    PersistentSet
    什么时候会被刷新/重新刷新
  • 我们如何在应用程序代码中确定我们没有处理持久性缓存问题
  • 在孩子的自然id中包含父母是否不好
  • Parent::addChild
    中反转操作顺序是否有任何副作用
  • 提前谢谢你的建议