OpenJPA OneToMany and composite key in parent and child tables

I have tables with a composite primary key.

Server(key=ServerId)
ServerId|Name
1       |server1
2       |server2
ParentObj(key=ServerId+Code)
ServerId|Code |Title
1       |code1|value1
1       |code2|value2
2       |code1|Value2b
ChildObj(key=ServerId+Code+Name)
ServerId|Code |Name |Value
1       |code1|prop1|val1
1       |code1|prop2|val2
1       |code2|prop1|val1b
2       |code1|prop3|val3

      

These are Java beans I have.

@Entity @Table(name="ParentObj") @Access(AccessType.FIELD)
@IdClass(value=ParentObj.PK.class)
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlRootElement
public class ParentObj {
   @Id private long serverId;
   @Id private String code;
   private String title;

   public long getServerId() { return serverId; }
   public String getCode() { return code; }
   public String getTitle() { return title; }

   public static class PK implements Serializable {
     private static final long serialVersionUID = 1L;       
     private long serverId;
     private String code;

     public long getServerId() { return serverId; }
     public void setServerId(long id) { serverId=id; }
     public String getCode() { return code; }
     public void setCode(String code) { this.code=code; }
  }
}

@Entity @Table(name="ChildObj") @Access(AccessType.FIELD)
@IdClass(value=ChildObj.PK.class)
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
@XmlRootElement
public class ChildObj {
   @Id private long serverId;
   @Id private String code;
   @Id private String name;
   private String value;
   // public getter+setters for each field

   public static class PK implements Serializable {
     private static final long serialVersionUID = 1L;       
     private long serverId;
     private String code;
     private String name;

     public long getServerId() { return serverId; }
     public void setServerId(long id) { serverId=id; }
     public String getCode() { return code; }
     public void setCode(String code) { this.code=code; }
     public String getName() { return name; }
     public void setName(String name) { this.name=name; }
  }
}

      

I am trying to create "everything" to create OneToMany maps (ParentObj-> ChildObj) but nothing seems to work. I don't need the ManyToOne reference (ParentObj <-ChildObj), but that's ok if you need to define.

This is a legacy database, so I cannot insert an auto_increment identity column or create an additional parent-child join table.

This annotation is conceptually what I want, but multiple join columns are not accepted by the OpenJPA2.x library.

// from parent to zero or more childs
@OneToMany(fetch=FetchType.LAZY)
@JoinColumns({
    @JoinColumn(name="server_id", referencedColumnName="server_id"),
    @JoinColumn(name="code", referencedColumnName="code")
})
private List<ChildObj> properties;

      

Edit, answer OneToMany, ManyToOne and EmbeddedId work. I only tried reading existing lines, but now this is fine. Later I will try to update + insert + delete tasks.

public class ParentObj {
   @EmbeddedId ParentObj.PK pk;
   @OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="parent", orphanRemoval=true)
   private List<ChildObj> childs;

   public PK getPK() { return pk; }
   public void setPK(PK pk) { this.pk=pk; }
   public List<ChildObj> getChilds() { return childs; }
   ...

   @Embeddable @Access(AccessType.FIELD)
   public static class PK implements Serializable {    
       private static final long serialVersionUID = 1L;     
       @Column(nullable=false) private long serverId;
       @Column(nullable=false) private String code;
       ..getters+setters+hashCode+equals functions
   }
}

public class ChildObj {
   @EmbeddedId ChildObj.PK pk;
   @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST, optional=false)
      @JoinColumns({
      @JoinColumn(name="serverid", referencedColumnName="serverid", nullable=false), 
      @JoinColumn(name="code", referencedColumnName="code", nullable=false)
   })   
   private ParentObj parent;

   public PK getPK() { return pk; }
   public void setPK(PK pk) { this.pk=pk; }
   public long getServerId() { return pk.getServerId(); }
   public String getCode() { return pk.getCode(); }
   public String getName() { return pk.getName(); }
   ...

   @Embeddable @Access(AccessType.FIELD)
   public static class PK implements Serializable {
      private static final long serialVersionUID = 1L;      
      @Column(nullable=false) private long serverId;
      @Column(nullable=false) private String code;
      @Column(nullable=false) private String name;
      ..getters+setters+hashCode+equals functions
   }
}

      

+3


source to share


1 answer


The easiest way to do this is to create a link from ChildObj

to ParentObj

, as shown below:

@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JoinColumns({
    @JoinColumn(name = "serverId", referencedColumnName = "serverId"),
    @JoinColumn(name = "code", referencedColumnName = "code")})
private ParentObj parentObj;

      

and then define the association @OneToMany

in the ParentObj

following way:



@OneToMany(mappedBy = "parentObj", fetch=FetchType.LAZY)
private List<ChildObj> children;

      

I would also recommend that you define composite keys as @Embeddable

classes used as @EmbeddedId

references in Entities. These inline PK classes should be separate classes (not inner classes), as you will be using them separately to query related objects, and serializing inner classes can cause problems

+1


source







All Articles