【问题标题】:OpenJPA OneToMany and composite key in parent and child tableOpenJPA OneToMany 和父子表中的复合键
【发布时间】:2015-09-08 07:37:48
【问题描述】:

我有带有复合主键的表。

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

这是我拥有的 Java bean。

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

我一直在尝试“一切”来创建 OneToMany 映射(ParentObj->ChildObj),但似乎没有任何效果。我不需要 ManyToOne(ParentObj

这是一个旧数据库,因此我无法插入 auto_increment 标识列或在父子节点之间创建额外的连接表。

这个注释在概念上是我想要的,但 OpenJPA2.x 库不接受多个连接列。

// 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;

编辑、回答 OneToMany、ManyToOne 和 EmbeddedId 注释有效。我只尝试阅读现有的行,但现在还可以。后来我尝试更新+插入+删除任务。

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

【问题讨论】:

  • 最简单的方法是创建一个从ChildObjParentObj@ManyToOne 关联,然后将mappedBy 用于ParentObj 中的@oneToMany。另外,我建议您使用 @EmbeddedId@Embeddable PK 类。
  • 它可以工作,并且 EmbeddedId 重复的代码更少。谢谢。如果您发布答案,我可以正确接受。
  • 我已经发布了一个答案,但请注意您的 @Embeddable 类应该是一个单独的(而不是内部)类 - 请参阅我的答案。

标签: java jpa jpa-2.0 openjpa


【解决方案1】:

最简单的方法是创建一个从ChildObjParentObj 的关联,类似于以下内容:

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

然后像这样在ParentObj 中定义@OneToMany 关联:

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

我还建议您将复合键定义为@Embeddable 类,用作实体中的@EmbeddedId 引用。这些可嵌入的 PK 类应该是单独的类(不是内部类),因为您将单独使用它们来查询相关的实体,并且serialisation of inner classes can cause problems

【讨论】:

  • 我使用 public static class PK {...} 内部类(静态)并且检索似乎工作正常,暂时我在进行最终实现之前保持这种方式.
猜你喜欢
  • 2011-02-06
  • 1970-01-01
  • 2011-11-26
  • 1970-01-01
  • 2015-11-14
  • 2012-03-20
  • 1970-01-01
  • 2016-12-25
相关资源
最近更新 更多