由于缺少@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没有显示为declaredAttribute,尽管它似乎显示在id信息中。
我的复合键设置是否正确以及如何使用条件api查询复合键的一部分?
如果上面不清楚,目标是能够获得具有给定patronId
的所有Balance对象,即使patronId
只是复合键的一部分。
答案 0 :(得分:0)
我不确定这是否正确,但似乎有效。它是否正确?我对hibernate的了解有限。
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();
}