由于缺少@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();
}

09-27 02:04