在现实中咱们可能会遇到许多表多是没有主键的,那么咱们对其作映射后使用会是什么样的结果?能正常获得咱们想要的吗?结果应该是得不到想要的结果,而获得的可能会是以下的报错:java
Caused by:org.hibernate.AnnotationException: No identifier specified for entity: xxx.xxx.xxxide
这个结果告诉咱们:Hibernate映射表是须要主键的。测试
因此复合主键映射就应运而生了。this
复合主键使用一个可嵌入的类做为主键表示,所以你须要使用@Id和@Embeddable两个注解.还有一种方式是使用@EmbeddedId注解.固然还有一种方法那就是——使用@IdClass注解。具体请查看【hibernate-annotations-3.4.0.GA 2.2.6.映射复合主键与外键】。spa
固然,只须要选择其中的一种就能够了。^_^.net
注意所依赖的类必须实现 serializable以及实现equals()/hashCode()方法.hibernate
举一个具体事例:code
package com.sourcefour.bean; // default package import javax.persistence.AttributeOverride; import javax.persistence.AttributeOverrides; import javax.persistence.Column; import javax.persistence.EmbeddedId; import javax.persistence.Entity; import javax.persistence.Table; /** * User entity. @author MyEclipse Persistence Tools */ @Entity @Table(name="t_user_composite_pk" ) public class User implements java.io.Serializable { // Fields private UserId id; // Constructors /** default constructor */ public User() { } /** full constructor */ public User(UserId id) { this.id = id; } // Property accessors @EmbeddedId @AttributeOverrides( { @AttributeOverride(name="intId", column=@Column(name="intId", nullable=false) ), @AttributeOverride(name="varcName", column=@Column(name="varcName", length=50) ), @AttributeOverride(name="varcAddress", column=@Column(name="varcAddress", length=50) ), @AttributeOverride(name="intAge", column=@Column(name="intAge", nullable=false) ) } ) public UserId getId() { return this.id; } public void setId(UserId id) { this.id = id; } }
2.2. UserId.javablog
package com.sourcefour.bean; // default package import javax.persistence.Column; import javax.persistence.Embeddable; /** * UserId entity. @author MyEclipse Persistence Tools */ @Embeddable public class UserId implements java.io.Serializable { // Fields private int intId; private String varcName; private String varcAddress; private int intAge; // Constructors /** default constructor */ public UserId() { } /** minimal constructor */ public UserId(int intId, int intAge) { this.intId = intId; this.intAge = intAge; } /** full constructor */ public UserId(int intId, String varcName, String varcAddress, int intAge) { this.intId = intId; this.varcName = varcName; this.varcAddress = varcAddress; this.intAge = intAge; } // Property accessors @Column(name = "intId", nullable = false) public int getIntId() { return this.intId; } public void setIntId(int intId) { this.intId = intId; } @Column(name = "varcName", length = 50) public String getVarcName() { return this.varcName; } public void setVarcName(String varcName) { this.varcName = varcName; } @Column(name = "varcAddress", length = 50) public String getVarcAddress() { return this.varcAddress; } public void setVarcAddress(String varcAddress) { this.varcAddress = varcAddress; } @Column(name = "intAge", nullable = false) public int getIntAge() { return this.intAge; } public void setIntAge(int intAge) { this.intAge = intAge; } public boolean equals(Object other) { if ((this == other)) return true; if ((other == null)) return false; if (!(other instanceof UserId)) return false; UserId castOther = (UserId) other; return (this.getIntId() == castOther.getIntId()) && ((this.getVarcName() == castOther.getVarcName()) || (this.getVarcName() != null && castOther.getVarcName() != null && this.getVarcName().equals(castOther.getVarcName()))) && ((this.getVarcAddress() == castOther.getVarcAddress()) || (this.getVarcAddress() != null && castOther.getVarcAddress() != null && this.getVarcAddress().equals( castOther.getVarcAddress()))) && (this.getIntAge() == castOther.getIntAge()); } public int hashCode() { int result = 17; result = 37 * result + this.getIntId(); result = 37 * result + (getVarcName() == null ? 0 : this.getVarcName().hashCode()); result = 37 * result + (getVarcAddress() == null ? 0 : this.getVarcAddress().hashCode()); result = 37 * result + this.getIntAge(); return result; } }
3. 可能还会出现的问题ip
具体来讲问题就是查询出来的结果列表为‘null’(这一点我此次在我机器上测试时没有出现)。
若是出现了该问题,那么看到这一点就应该能解决问题啦,若是不出现那就更好,呵呵!
可是我的以为这一点应该仍是得说的。^_^
有时候查询出来的结果列表为‘null’,这使人非常费解,能够想下这是什么缘由?
直接上缘由,嘎嘎……。
缘由:做为联合主键的字段理论上不该该包含可能为空的字段。
缘由分析:根据缘由,说明实体Bean中的某个(些)对应的表字段有空值。
解决方案:只须要将可能为空的字段不做为联合主键的一部分就能够。
说的估计晕头了吧,直接来个事例吧(我的一直以为,例子是解释问题的最好说明)。
假设表中的varcName和varcAddress是可能为空的,其它都不可能为空,那么映射应该是这样的
User.java
…… private UserId id; private String varcName; private String varcAddress; …… /* 这里加入varcName和varcAddress映射内容,嗯仍是贴出来吧,反正电子档的又不怕木有地方,嘎嘎…… */ @Column(name="varcName", length=50) public String getVarcName() { return this.varcName; } public void setVarcName(String varcName) { this.varcName = varcName; } @Column(name="varcAddress", length=50) public String getVarcAddress() { return this.varcAddress; } public void setVarcAddress(String varcAddress) { this.varcAddress = varcAddress; }
UserId.java