开发者

How to get Hibernate JPA to manage list index automagically?

开发者 https://www.devze.com 2022-12-12 19:04 出处:网络
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?

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 tha开发者_如何学Got 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?


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


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);
        }
    }
}


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 has been deprecated a long time ago and in its place it is best recommended using the @OrderColumn annotation. The second annotation not only simplifies its syntax without having to specify the base attribute, but it also avoids declaring an extra field in the detail class, in this case the policySequence field within the Policy class.

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;

    @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;
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消