由于缺少@Id
批注,我们最近在软件中遇到了一个错误:
@Entity
@Table (name ="PATRONQRSPLANS")
//@IdClass(PatronPlan.class) <-- this was missing
public class Balance {
@Transient
private String kind;
@Transient
private String planName;
@Transient
private PlanCategory planCategory;
@Id
@Column(name="PATRONID")
private int patronId;
//@Id <--- and this was missing
@Column(name="PLANID")
private int planId;
@Column(name="BALANCE")
private int balance;
@Column(name="ENDDATE")
private Date expirationDate;
public Balance() {
this.kind = "balance";
}
public Balance(int balance, int planId, Date expirationDate) {
this.balance = balance;
this.planId = planId;
this.expirationDate = expirationDate;
this.kind = "balance";
}
public int getPatronId() {
return patronId;
}
public void setPatronId(int patronId) {
this.patronId = patronId;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public int getPlanId() {
return planId;
}
public void setPlanId(int planId) {
this.planId = planId;
}
public String getPlanName() {
return planName;
}
public void setPlanName(String planName) {
this.planName = planName;
}
public String getKind() {
return kind;
}
public void setKind(String kind) {
this.kind = kind;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
public PlanCategory getPlanCategory() {
return planCategory;
}
public void setPlanCategory(PlanCategory planCategory) {
this.planCategory = planCategory;
}
}
问题在于该表在planId和patronId上都具有主键约束,因此我需要一个复合键。对于具有2个不同计划的顾客,以下查询(没有上面的注释注释)将返回2个相同计划的副本,而不是2个不同的计划。
public List<Balance> getBalancesByPatronId(int patronId) {
CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Balance> query = builder.createQuery(Balance.class);
Root<Balance> s = query.from(Balance.class);
query.select(s);
query.where(builder.equal(s.get("patronId"), patronId));
return entityManager.createQuery(query).getResultList();
}
为了解决这个问题,我添加了上面注释的
@Id
和@IdClass
注释,并创建了此类:public class PatronPlan implements Serializable {
private static final long serialVersionUID = -3518083815234439123L;
@Id
@Column(name="PATRONID")
private int patronId;
@Id
@Column(name="PLANID")
private int planId;
public int getPatronId() {
return patronId;
}
public void setPatronId(int patronId) {
this.patronId = patronId;
}
public int getPlanId() {
return planId;
}
public void setPlanId(int planId) {
this.planId = planId;
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (!this.getClass().isAssignableFrom(obj.getClass())) return false;
PatronPlan other = (PatronPlan) obj;
return Objects.equals(patronId, other.getPatronId()) && Objects.equals(planId, other.getPlanId());
}
@Override
public int hashCode() {
return Objects.hash(patronId, planId);
}
}
但是现在我在该语句的critera查询中得到了NullPointerException
s.get("patronId")
,因为patronId似乎并未显示在id信息中,但并未显示为clarifiedAttribute。我的组合键设置是否正确?如何使用条件api查询组合键的一部分?
如果上面不清楚,则目标是即使给定
patronId
只是组合键的一部分,也能够使用给定的patronId
获取所有Balance对象。 最佳答案
我不确定这是否正确,但似乎可行。它是否正确?我对休眠的了解有限。
public List<Balance> getBalancesByPatronId(int patronId) {
CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Balance> query = builder.createQuery(Balance.class);
Metamodel metaModel = getEntityManager().getMetamodel();
SingularAttribute<Balance, Integer> patronIdAttr =
(SingularAttribute<Balance, Integer>) metaModel.entity(Balance.class)
.getIdClassAttributes().toArray()[0];
Root<Balance> s = query.from(Balance.class);
query.select(s);
query.where(builder.equal(s.get(patronIdAttr), patronId));
return entityManager.createQuery(query).getResultList();
}