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
}
}
source to share
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
source to share