如何让 Hibernate JPA 自动管理列表索引?

发布于 2024-08-12 15:07:56 字数 2549 浏览 6 评论 0原文

如何使用列表设置基本的一对多关系并让 Hibernate JPA 自动管理列表的序列索引号?这可以做到吗?

这是我的测试用例(或多或少);

@Table(name="Policy_Root")
public class PolicyRoot extends BaseDomainModel {

    private List<Policy> policyList = new ArrayList<Policy>();

    @OneToMany(targetEntity=Policy.class, mappedBy="policyRoot", cascade=CascadeType.ALL)
    @IndexColumn(name="policy_sequence", base=0, nullable=false)
    public List<Policy> getPolicyList() {
        return policyList;
    }

    public void setPolicyList(List<Policy> policyList) {
        this.policyList = policyList;
    }

    public void addPolicy(Policy policy) {
        policyList.add(policy);
        policy.setPolicyRoot(this);
    }

    public void addPolicy(int sequence, Policy policy) {
        policyList.add(sequence, policy);
        policy.setPolicyRoot(this);
    }
}

@Entity()
@Table(name="Policy")
public class Policy extends BaseDomainModel {

    /** The position of this policy record within the list of policy's belong to the parent PolicyRoot    */
    private int policySequence;

    /** Birectional pointer to parent */
    private PolicyRoot policyRoot;

    @Column(name="policy_sequence")
    public int getPolicySequence() {
        return policySequence;
    }

    public void setPolicySequence(int policySequence) {
        this.policySequence = policySequence;
    }

    @ManyToOne
    @JoinColumn(name="policy_root_oid", nullable=false)
    public PolicyRoot getPolicyRoot() {
        return policyRoot;
    }

    public void setPolicyRoot(PolicyRoot policyRoot) {
        this.policyRoot = policyRoot;
    }
}


    @Test
    public void testCreation() {
        Policy policy1 = new Policy();
        Policy policy2 = new Policy();

        // Uncomment the following and the test case works - but I don't want to manage the sequence numbers
        //policy2.setPolicySequence(1);

        PolicyRoot policyRoot = new PolicyRoot();
        policyRoot.addPolicy(policy1);
        policyRoot.addPolicy(policy2);

        ServiceImplFacade.getPersistenceFacade().persistSingleItem(policyRoot);
        Long oid = policyRoot.getOid();
        PolicyRoot policyRootFromDB = ServiceImplFacade.getPersistenceFacade().getEntityManager().find(PolicyRoot.class, oid);

        assertEquals(2, policyRootFromDB.getPolicyList().size());
    }

如果我取消注释policy2.setPolicySequence(1);行然后测试用例通过,但我认为我不需要这样做。我希望 Hibernate 为我做这件事。我的理解是它可以,但如果它不能,那么知道它不能也是一个很好的答案。

我尝试过设置可为空、可插入和可更新的各种组合,但我可能错过了其中一种。

这可能吗? - 如果是这样怎么办?

How do I setup a basic OneToMany relationship using a List and get Hibernate JPA to manage the sequence index number of the list automagically? Can this be done?

This is my test case (more or less);

@Table(name="Policy_Root")
public class PolicyRoot extends BaseDomainModel {

    private List<Policy> policyList = new ArrayList<Policy>();

    @OneToMany(targetEntity=Policy.class, mappedBy="policyRoot", cascade=CascadeType.ALL)
    @IndexColumn(name="policy_sequence", base=0, nullable=false)
    public List<Policy> getPolicyList() {
        return policyList;
    }

    public void setPolicyList(List<Policy> policyList) {
        this.policyList = policyList;
    }

    public void addPolicy(Policy policy) {
        policyList.add(policy);
        policy.setPolicyRoot(this);
    }

    public void addPolicy(int sequence, Policy policy) {
        policyList.add(sequence, policy);
        policy.setPolicyRoot(this);
    }
}

@Entity()
@Table(name="Policy")
public class Policy extends BaseDomainModel {

    /** The position of this policy record within the list of policy's belong to the parent PolicyRoot    */
    private int policySequence;

    /** Birectional pointer to parent */
    private PolicyRoot policyRoot;

    @Column(name="policy_sequence")
    public int getPolicySequence() {
        return policySequence;
    }

    public void setPolicySequence(int policySequence) {
        this.policySequence = policySequence;
    }

    @ManyToOne
    @JoinColumn(name="policy_root_oid", nullable=false)
    public PolicyRoot getPolicyRoot() {
        return policyRoot;
    }

    public void setPolicyRoot(PolicyRoot policyRoot) {
        this.policyRoot = policyRoot;
    }
}


    @Test
    public void testCreation() {
        Policy policy1 = new Policy();
        Policy policy2 = new Policy();

        // Uncomment the following and the test case works - but I don't want to manage the sequence numbers
        //policy2.setPolicySequence(1);

        PolicyRoot policyRoot = new PolicyRoot();
        policyRoot.addPolicy(policy1);
        policyRoot.addPolicy(policy2);

        ServiceImplFacade.getPersistenceFacade().persistSingleItem(policyRoot);
        Long oid = policyRoot.getOid();
        PolicyRoot policyRootFromDB = ServiceImplFacade.getPersistenceFacade().getEntityManager().find(PolicyRoot.class, oid);

        assertEquals(2, policyRootFromDB.getPolicyList().size());
    }

If I uncomment the policy2.setPolicySequence(1); line then the test case passes, but I don't think I need to do this. I want Hibernate to do this for me. My understanding is that it can, but if it can't then knowing that it can't would be a good answer as well.

I've tried various combinations of setting nullable, insertable and updateable but I may have missed one.

Is this possible? - If so how?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

中二柚 2024-08-19 15:07:56

找到了答案——它是关于获得可为空和可插入的正确组合。还必须在 Integer 处创建“子索引”,以便它可以为空,并且下面还有一个“可选”标志。

public class PolicyRoot extends BordereauxBaseDomainModel {

     private List<Policy> policyList = new ArrayList<Policy>();

    @OneToMany(cascade=CascadeType.ALL)
    @IndexColumn(name="policy_sequence", nullable=false, base=0)
    @JoinColumn(name="policy_root_oid", nullable=false)
    public List<Policy> getPolicyList() {
        return policyList;
    }

    public void setPolicyList(List<Policy> policyList) {
        this.policyList = policyList;
    }
}


public class Policy extends BordereauxBaseDomainModel {

    /** The position of this policy record within the list of policy's belong to the parent PolicyRoot    */
    private Integer policySequence;

    /** Birectional pointer to parent */
    private PolicyRoot policyRoot;

    @Column(name="policy_sequence", insertable=false, updatable=false)
    public Integer getPolicySequence() {
        return policySequence;
    }

    public void setPolicySequence(Integer policySequence) {
        this.policySequence = policySequence;
    }

    @ManyToOne(optional=false)
    @JoinColumn(name="policy_root_oid", insertable=false, updatable=false, nullable=false)
    public PolicyRoot getPolicyRoot() {
        return policyRoot;
    }

    public void setPolicyRoot(PolicyRoot policyRoot) {
        this.policyRoot = policyRoot;
    }
}

在谷歌搜索了一段时间后,在下一页找到了答案。

http://opensource.atlassian.com/projects/hibernate/browse/HHH- 4390

Found the answer, - it was around getting the right combinations of nullable and insertable. Also had to make the "child index" at Integer so that it could be nullable, and there's also an "optional" flag in the following as well.

public class PolicyRoot extends BordereauxBaseDomainModel {

     private List<Policy> policyList = new ArrayList<Policy>();

    @OneToMany(cascade=CascadeType.ALL)
    @IndexColumn(name="policy_sequence", nullable=false, base=0)
    @JoinColumn(name="policy_root_oid", nullable=false)
    public List<Policy> getPolicyList() {
        return policyList;
    }

    public void setPolicyList(List<Policy> policyList) {
        this.policyList = policyList;
    }
}


public class Policy extends BordereauxBaseDomainModel {

    /** The position of this policy record within the list of policy's belong to the parent PolicyRoot    */
    private Integer policySequence;

    /** Birectional pointer to parent */
    private PolicyRoot policyRoot;

    @Column(name="policy_sequence", insertable=false, updatable=false)
    public Integer getPolicySequence() {
        return policySequence;
    }

    public void setPolicySequence(Integer policySequence) {
        this.policySequence = policySequence;
    }

    @ManyToOne(optional=false)
    @JoinColumn(name="policy_root_oid", insertable=false, updatable=false, nullable=false)
    public PolicyRoot getPolicyRoot() {
        return policyRoot;
    }

    public void setPolicyRoot(PolicyRoot policyRoot) {
        this.policyRoot = policyRoot;
    }
}

Found the answers on the following page after searching Google for a while.

http://opensource.atlassian.com/projects/hibernate/browse/HHH-4390

波浪屿的海角声 2024-08-19 15:07:56

做这样的事情:

@Entity
class Parent {

    @OneToMany
    @IndexColumn(name = "index_column")
    List<Child> children;
}

@Entity
class Child {

    @ManyToOne
    Parent parent;
    @Column(name = "index_column")
    Integer index;

    @PrePersist
    @PreUpdate
    private void prepareIndex() {
        if (parent != null) {
            index = parent.children.indexOf(this);
        }
    }
}

Do something like this:

@Entity
class Parent {

    @OneToMany
    @IndexColumn(name = "index_column")
    List<Child> children;
}

@Entity
class Child {

    @ManyToOne
    Parent parent;
    @Column(name = "index_column")
    Integer index;

    @PrePersist
    @PreUpdate
    private void prepareIndex() {
        if (parent != null) {
            index = parent.children.indexOf(this);
        }
    }
}
如何视而不见 2024-08-19 15:07:56

我将发布这个答案,因为我最近遇到了同样的问题,并且这个问题虽然已经过时,但在研究中不断出现。

@IndexColumn 注释已弃用很久以前。事实上,实际上建议使用 @OrderColumn 注释代替。第二个注释不仅简化了语法而不必指定 base 属性,而且还避免了在详细信息类中声明额外的字段(policySequence 字段在详细信息类中)在本例中为 >Policy 类)。这是因为,有了@OrderColumn注解,Hibernate会自动理解在Policy表中声明一个字段,并用注解的属性name来命名它。并使用对象在列表中覆盖的索引对其进行初始化。

这是之前代码片段的更新版本:

@Table(name = "Policy_Root")
public class PolicyRoot extends BaseDomainModel {

    private List<Policy> policyList = new ArrayList<Policy>();

    @OneToMany(targetEntity = Policy.class, mappedBy = "policyRoot", cascade = CascadeType.ALL)
    @OrderColumn(name = "policy_sequence", nullable = false)
    public List<Policy> getPolicyList() {
        return policyList;
    }

    public void setPolicyList(List<Policy> policyList) {
        this.policyList = policyList;
    }

    public void addPolicy(Policy policy) {
        policyList.add(policy);
        policy.setPolicyRoot(this);
    }

    public void addPolicy(int sequence, Policy policy) {
        policyList.add(sequence, policy);
        policy.setPolicyRoot(this);
    }
}

@Entity()
@Table(name = "Policy")
public class Policy extends BaseDomainModel {

    //No need to declare the policySequence field

    /** Birectional pointer to parent */
    private PolicyRoot policyRoot;

    @ManyToOne
    @JoinColumn(name="policy_root_oid", nullable=false)
    public PolicyRoot getPolicyRoot() {
        return policyRoot;
    }

    public void setPolicyRoot(PolicyRoot policyRoot) {
        this.policyRoot = policyRoot;
    }
}

I'm going to post this answer since I recently had the same issue and this question, although outdated, keeps coming up in the researches.

The @IndexColumn annotation was deprecated a long time ago. In fact, it is actually recommended to use the @OrderColumn annotation instead. This second annotation not only simplifies the syntax without having to specify the base attribute, but it also avoids declaring an extra field in the detail class (the policySequence field within the Policy class in this case). This is because, with the @OrderColumn annotation, Hibernate automatically understands to declare a field in the Policy table, name it with the annotation's attribute name and initialize it with the index that the object covers within the List.

Here is the updated version of the previous snippet:

@Table(name = "Policy_Root")
public class PolicyRoot extends BaseDomainModel {

    private List<Policy> policyList = new ArrayList<Policy>();

    @OneToMany(targetEntity = Policy.class, mappedBy = "policyRoot", cascade = CascadeType.ALL)
    @OrderColumn(name = "policy_sequence", nullable = false)
    public List<Policy> getPolicyList() {
        return policyList;
    }

    public void setPolicyList(List<Policy> policyList) {
        this.policyList = policyList;
    }

    public void addPolicy(Policy policy) {
        policyList.add(policy);
        policy.setPolicyRoot(this);
    }

    public void addPolicy(int sequence, Policy policy) {
        policyList.add(sequence, policy);
        policy.setPolicyRoot(this);
    }
}

@Entity()
@Table(name = "Policy")
public class Policy extends BaseDomainModel {

    //No need to declare the policySequence field

    /** Birectional pointer to parent */
    private PolicyRoot policyRoot;

    @ManyToOne
    @JoinColumn(name="policy_root_oid", nullable=false)
    public PolicyRoot getPolicyRoot() {
        return policyRoot;
    }

    public void setPolicyRoot(PolicyRoot policyRoot) {
        this.policyRoot = policyRoot;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文