使用Hibernate和JPA的祖父到子Map

tez616oj  于 2023-05-18  发布在  其他
关注(0)|答案(1)|浏览(116)

我使用Spring、Hibernate和JPA。(我会提到这是一个dropwizard应用程序,而不是springboot,尽管我不认为它应该有任何影响。
存储:MySql.
数据库中没有使用外键。

注意:

正如下面的一条评论所提到的,我完全同意将祖父母ID保存在子表中并不理想,遍历child -> parent -> grandparent是一个更好的做法。特别是对于这个问题,请考虑这是一个给定的情况(一种遗留代码,我现在不能改变…)
我有以下JPA实体:(姓名已更改)

祖父母:

@Entity
public class GrandParent {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "id", columnDefinition = "int unsigned not null")
    private Long id;

    //... some other fields... getters and setters

    @OneToMany(mappedBy = "parent",
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    private Set<Parent> parents;

    public void addParent(Parent parent) {
        if (this.parents == null) {
            this.parents = new HashSet<>();
        }
        this.parents.add(parent);
        parent.setGrandParent(this);
    }

    public void removeParent(Parent parent) {
        this.parents.remove(parent);
        parent.setGrandParent(null);
    }

}

父节点:

@Entity
public class Parent {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "id", columnDefinition = "int unsigned")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "grand_parent_id", referencedColumnName = "id", columnDefinition = "int unsigned")
    private GrandParent grandParent;
   
    @OneToMany(mappedBy = "parent",
            cascade = CascadeType.ALL,
            orphanRemoval = true
    )
    private Set<Child> children;

    // other fields, getters and setters

    public void addChild(Child child) {
        if (this.fields == null) {
            this.fields = new HashSet<>();
        }
        this.children.add(child);
        child.setParent(this);
    }

    public void removeChild(Child child) {
        this.children.remove(child);
        child.setParent(null);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Parent )) return false;
        return id != null && id.equals(((Parent) o).getId());
    }

    @Override
    public int hashCode() {
        return getClass().hashCode();
    }

}

孩子:

@Entity
public class Child {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(name = "id", columnDefinition = "int unsigned")
    private Long id;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "grand_parent_id", columnDefinition = "int unsigned")
    private GrandParent grandParent;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id", columnDefinition = "int unsigned")
    private Parent parent;

    // other fields, getters and setters

}

我以以下方式创建了一个GrandParent instant(我只提到了相关的字段...):

Child child = Child.builder()
                .someField("1")
                .someOtherField(1)
                .build();

Parent parent = Parent.builder()
                .someField("1")
                .someOtherField(1)
                .build();
        parent.addChild(child);
        
GrandParent grandParent = GrandParent.builder()
                .someField("1")
                .someOtherField(1)
                .build();
        grandParent.addParent(parent);

在“我的存储库”中,我使用以下命令保存祖父实体:

hibernateSession.save(grandParent);

事实上,所有行都成功存储,但child.grand_parent_id仍然为Null。
出了什么问题,如何解决?

为了更好的可见性,我添加了此更新(请参阅下面的@MauricioBuffon评论)

我试图通过编辑Parent Entity中的addChild方法来显式地在Child中设置GrandParent

public void addChild(Child child) { 
        if (this.children == null) {             
             this.children = new HashSet<>();         
        }         
        this.children.add(child);         
        child.setParent(this);
        //let's try...
        child.setGrandParent(getGrandParent());
     }

仍然是子项。grand_parent_id = Null。
所以问题依然存在:
出了什么问题,如何解决?

rt4zxlrg

rt4zxlrg1#

根本原因-我没有在子节点上显式设置grandParent。在这些实体之间建立一对一的单向关系,这是要走的路。
作者:MauricioBuffon

public void addParent(Parent parent) {
        if (this.parents == null) {
            this.parents = new HashSet<>();
        }
        this.parents.add(parent);
        parent.setGrandParent(this);
        parent.getChildren().stream().forEach(child -> child.setGrandParent(this));
    }

相关问题