1

Wir haben vor kurzem über einen Fehler in unserer Software aufgrund eines fehlenden @Id Anmerkung lautete:Criteria Abfrage auf einem Teil eines zusammengesetzten Schlüssel

@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; 
    } 
} 

Das Problem ist, dass die Tabelle auf beiden planId und patronId eine Primärschlüsselbedingung hat , also brauche ich einen zusammengesetzten Schlüssel. Die Abfrage unten (ohne die oben genannten Anmerkungen) für einen Benutzer, der 2 verschiedene Pläne hat, gibt 2 Kopien desselben Plans anstelle von 2 verschiedenen zurück.

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(); 
} 

Um dies zu beheben, habe ich eine @Id und @IdClass Anmerkung wie oben auf Kommentar, sowie die Schaffung dieser Klasse:

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); 
    } 

}

Aber jetzt bekomme ich eine Nullpointer in meinem critera Abfrage auf die Anweisung s.get("patronId"), weil patronId nicht als deklariertesAttribut angezeigt wird, obwohl es scheint, in der ID-Informationen angezeigt werden.

Ist mein zusammengesetztes Schlüsselsetup korrekt und wie frage ich nach einem Teil eines zusammengesetzten Schlüssels mit den Kriterien api?

Wenn es oben nicht klar war, ist das Ziel, alle Balance-Objekte mit einem gegebenen patronId abrufen zu können, obwohl patronId nur ein Teil des zusammengesetzten Schlüssels ist.

Antwort

0

Ich bin mir nicht sicher, ob das richtig ist, aber es scheint zu funktionieren. Ist das richtig? Mein Wissen über den Winterschlaf ist begrenzt.

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(); 
} 
Verwandte Themen