最近我的博客老是搬家,最后还是回到开源中国的博客,真心对不起那些加过我贴子收藏的人,我悔过!希望我的贴子能帮助到和我遇到同样问题的朋友!
正题。如何用Hibernate实现复杂主键,@EmbeddedId、@IdClass用哪个实现?
一个表有多个主键,有外键,这个外键还是主键,其他的主键有一个还是自动产生id的,我遇到这个问题要设计实体类的时候也是醉了~
当然反向生成实体类方便很多。但是生成的实体类复合主键用的都是@EmbeddedId、和@Embeddable注解。这种注解需要手动new一个被@Embeddable注解的嵌入类,set完属性后将这个嵌入对象set给@EmbeddedId注解getter,不能使是其中的属性自动产生值。
我一开始找的办法是怎么在被@EmbeddedId或@Embeddable注解的类添加序列或uuid,后来查JPA文档才想起了注解ID还有个@IdClass。发现改写还挺容易的,下面是简化的例子。
反向生成被@EmbeddedId或@Embeddable注解的类:
表对应的实体类:
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import com.kcomdata.entity.PdBvd;
import com.kcomdata.entity.PdBvdIndId;
@Entity
@Table(name = "PD_BVD_IND")
public class PdBvdInd implements java.io.Serializable {
private PdBvdIndId id;// 这一个联合主键嵌入的类,存放多个主键。
private PdBvd pdBvd;// 这个会产生一个外键字段BVD_ID,但是表中它还是个主键。
/**
* 嵌套进来的PdBvdIndId类,其属性是多个主键,其中BVD_ID和外键是同一个,所以就同时是主键,ID字段需要使用uuid生成。
*/
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "bvdId", column = @Column(name = "BVD_ID", nullable = false, length = 50)),
@AttributeOverride(name = "type", column = @Column(name = "TYPE", nullable = false, length = 50)),
@AttributeOverride(name = "id", column = @Column(name = "ID", nullable = false, precision = 19)) })
public PdBvdIndId getId() {
return this.id;
}
public void setId(PdBvdIndId id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "BVD_ID", nullable = false, insertable = false, updatable = false)
public PdBvd getPdBvd() {
return this.pdBvd;
}
public void setPdBvd(PdBvd pdBvd) {
this.pdBvd = pdBvd;
}
}
实体类的ID嵌入类:
import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@Embeddable
public class PdBvdIndId implements java.io.Serializable {
private String bvdId;
private String type;
private BigDecimal id;
@Column(name = "BVD_ID", nullable = false, length = 50)
public String getBvdId() {
return this.bvdId;
}
public void setBvdId(String bvdId) {
this.bvdId = bvdId;
}
@Column(name = "TYPE", nullable = false, length = 50)
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
@Column(name = "ID", nullable = false, precision = 19)
public BigDecimal getId() {
return id;
}
public void setId(BigDecimal id) {
this.id = id;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof PdBvdIndId))
return false;
PdBvdIndId castOther = (PdBvdIndId) other;
return ((this.getBvdId() == castOther.getBvdId()) || (this.getBvdId() != null
&& castOther.getBvdId() != null && this.getBvdId().equals(castOther.getBvdId())))
&& ((this.getType() == castOther.getType()) || (this.getType() != null
&& castOther.getType() != null && this.getType()
.equals(castOther.getType())))
&& ((this.getId() == castOther.getId()) || (this.getId() != null
&& castOther.getId() != null && this.getId().equals(castOther.getId())));
}
public int hashCode() {
int result = 17;
result = 37 * result + (getBvdId() == null ? 0 : this.getBvdId().hashCode());
result = 37 * result + (getType() == null ? 0 : this.getType().hashCode());
result = 37 * result + (getId() == null ? 0 : this.getId().hashCode());
return result;
}
}
生成的这两个类不能满足其中一个主键用uuid、序列或自动增长生成。改写成@IdClass的步骤:
表对应的实体类:
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import com.kcomdata.entity.PdBvd;
import com.kcomdata.entity.PdBvdIndId;
@Entity
@Table(name = "PD_BVD_IND")
@IdClass(PdBvdIndId.class)//指定id类
public class PdBvdInd implements java.io.Serializable {
/* 去掉那个主键类属性,将主键类属性全部搬过来 */
private String bvdId;//这个属性映射着pdBvd属性生成的外键字段,持久化时需要手动填值,不需要set入关联对象即调用getPdBvd()。
private String type;//这个主键持久化的时候需要手动填写。
private String id;//这个用uuid生成,但原表的类型是number(19),uuid需要用varchar存储,将原来的类型改成String。
private PdBvd pdBvd;// 这个会产生一个外键字段BVD_ID,但是表中它还是个主键。
/*这个不需要了删除掉
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "bvdId", column = @Column(name = "BVD_ID", nullable = false, length = 50)),
@AttributeOverride(name = "type", column = @Column(name = "TYPE", nullable = false, length = 50)),
@AttributeOverride(name = "id", column = @Column(name = "ID", nullable = false, precision = 19)) })
public PdBvdIndId getId() {
return this.id;
}
public void setId(PdBvdIndId id) {
this.id = id;
}*/
@ManyToOne(fetch = FetchType.LAZY)//这是外键,非空的。
@JoinColumn(name = "BVD_ID", nullable = false, insertable = false, updatable = false)
public PdBvd getPdBvd() {
return this.pdBvd;
}
public void setPdBvd(PdBvd pdBvd) {
this.pdBvd = pdBvd;
}
@Id//这个不需要生成策略,它映射着外键,插入时需要手动插入数据,外键也就有了数据,所以持久化时不需要调用getPdBvd()
@Column(name = "BVD_ID", nullable = false, length = 50)
public String getBvdId() {
return bvdId;
}
public void setBvdId(String bvdId) {
this.bvdId = bvdId;
}
@Id//这个不需要生成策略,但持久化时要手动set值
@Column(name = "TYPE", nullable = false, length = 50)
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Id//这个是用uuid自动生成
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
@Column(name = "ID", nullable = false)
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
@IdClass的复合组件类:
public class PdBvdIndId implements java.io.Serializable {
private String bvdId;
private String type;
private String id;//将原来的BigDecimal改成String,用来保存uuid。
public String getBvdId() {
return this.bvdId;
}
public void setBvdId(String bvdId) {
this.bvdId = bvdId;
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
/**
* 作为@IdClass的复合主键类,必须重写equals方法和hashCode(),但是从数据库反向生成的@Embeddable类也必须重写,
* 所以这里已经自动生成。
*/
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof PdBvdIndId))
return false;
PdBvdIndId castOther = (PdBvdIndId) other;
return ((this.getBvdId() == castOther.getBvdId()) || (this.getBvdId() != null
&& castOther.getBvdId() != null && this.getBvdId().equals(castOther.getBvdId())))
&& ((this.getType() == castOther.getType()) || (this.getType() != null
&& castOther.getType() != null && this.getType()
.equals(castOther.getType())))
&& ((this.getId() == castOther.getId()) || (this.getId() != null
&& castOther.getId() != null && this.getId().equals(castOther.getId())));
}
public int hashCode() {
int result = 17;
result = 37 * result + (getBvdId() == null ? 0 : this.getBvdId().hashCode());
result = 37 * result + (getType() == null ? 0 : this.getType().hashCode());
result = 37 * result + (getId() == null ? 0 : this.getId().hashCode());
return result;
}
}
表结构:
PD_BVD_IND | 表名 |
BVD_ID | varchar2(50) |
TYPE | varchar2(50) |
ID | varchar2(255) |
主键:BVD_ID、TYPE、ID(BVD_ID来自外键,TYPE手动填写,ID自动生成)
外键:BVD_ID