条件查询复合键的一部分

时间:2016-04-20 23:41:57

标签: java hibernate jpa hibernate-criteria hibernate-annotations

由于缺少@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只是复合键的一部分。

1 个答案:

答案 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();
}
相关问题