Einfache where-Bedingung für JPA CriteriaQuery

Dies ist mein Erster Versuch, JPA und ein CriteriaQuery.

Habe ich das folgende (vereinfachte) Unternehmen:

@Entity
@Table(name = "hours")
@XmlRootElement
public class Hours implements Serializable
{
    @EmbeddedId
    protected HoursPK hoursPK;

    @Column(name = "total_hours")
    private Integer totalHours;

    @JoinColumn(name = "trainer_id", referencedColumnName = "id", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private Trainer trainer;

    public Hours()
    {
    }

    ... getter and setter for the attributes
}

@Embeddable
public class HoursPK implements Serializable
{
    @Basic(optional = false)
    @Column(name = "date_held", nullable = false)
    @Temporal(TemporalType.DATE)
    private Date dateHeld;

    @Basic(optional = false)
    @Column(name = "trainer_id", nullable = false, length = 20)
    private String trainerId;

    @Column(name = "total_hours")
    private Integer totalHours;


    public HoursPK()
    {
    }

    ... getter and setter ...
}

@Entity
@Table(name = "trainer")
public class Trainer implements Serializable
{
    @Id
    @Basic(optional = false)
    @Column(name = "id", nullable = false, length = 20)
    private String id;

    @Basic(optional = false)
    @Column(name = "firstname", nullable = false, length = 200)
    private String firstname;

    @Basic(optional = false)
    @Column(name = "lastname", nullable = false, length = 200)
    private String lastname;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "trainer", fetch = FetchType.LAZY)
    private List<Hours> hoursList;

    ... more attributes, getters and setters

    @XmlTransient
    public List<Hours> getHoursList() {
       return hoursList;
    }

    public void setHoursList(List<Hours> hoursList) {
      this.hoursList = hoursList;
    }
}

Im wesentlichen eine Trainer hält Schulungen und die Stunden damit verbracht, die in den Schulungen werden gespeichert in der Hours Einheit. Die PK für die hours Tabelle (trainer_id, date_held) als jeder trainer enthält nur ein training pro Tag.

Ich versuche zu erstellen CriteriaQuery zu Holen, alle Stunden eines trainers für einen bestimmten Monat. Dies ist mein Versuch:

EntityManagerFactory emf = ...
EntityManager em = emf.createEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();

CriteriaQuery<Hours> c = builder.createQuery(Hours.class);

Root<Hours> root = c.from(Hours.class);

Calendar cal = Calendar.getInstance();
cal.set(2014, 0, 1);
Expression<Date> from = builder.literal(cal.getTime());

cal.set(2014, 1, 1);
Expression<Date> to = builder.literal(cal.getTime());

Predicate who = builder.equal(root.get(Hours_.trainer), "foobar"); //it fails here

Predicate gt = builder.greaterThanOrEqualTo(root.get(Hours_.hoursPK).get(HoursPK_.dateHeld), from);
Predicate lt = builder.lessThan(root.get(Hours_.hoursPK).get(HoursPK_.dateHeld), to);

c.where(gt,lt,who);
c.orderBy(builder.asc( root.get(Hours_.hoursPK).get(HoursPK_.dateHeld)  ));

TypedQuery<Hours> q = em.createQuery(c);

List<Hours> resultList = q.getResultList();

Ich bin mit Hibernate 4.3.1 als JPA-provider und der obige code bricht mit der Ausnahme:

Exception in thread "main" java.lang.IllegalArgumentException: Parameter Wert [foobar] passten nicht zu dem erwarteten Typ [Persistenz.Trainer (n/a)]
bei org.hibernate.jpa.spi.BaseQueryImpl.validateBinding(BaseQueryImpl.java:885)

Abgesehen von der Tatsache, dass dies scheint furchtbar kompliziert für eine Abfrage, die auch ein SQL newbie schreiben konnte, in ein paar Minuten, ich habe keine Ahnung, wie kann ich den korrekten Wert für die trainer_id Spalte in der hours Tabelle in der obigen Abfrage.

Ich auch versucht:

Predicate who = builder.equal(root.get("trainer_id"), "foobar");

Aber nicht, dass mit der Ausnahme:

java.lang.IllegalArgumentException: kann Nicht suchen Sie das Attribut mit dem angegebenen Namen [trainer_id] auf dieser ManagedType [Persistenz.Stunden]

Funktioniert es, wenn ich erhalten eine tatsächliche Entität-Instanz, die Karten auf den "foobar" id:

CriteriaQuery<Trainer> cq = builder.createQuery(Trainer.class);
Root<Trainer> trainerRoot = cq.from(Trainer.class);
cq.where(builder.equal(trainerRoot.get(Trainer_.id), "foobar"));
TypedQuery<Trainer> trainerQuery = em.createQuery(cq);  
Trainer foobarTrainer = trainerQuery.getSingleResult();
....
Predicate who = builder.equal(root.get(Hours_.trainer), foobarTrainer);

Aber das scheint eine ziemlich dumme (und langsamen) Weg, es zu tun.

Ich bin sicher, ich bin etwas fehlt offensichtlich wirklich hier, aber ich kann es nicht finden.

InformationsquelleAutor a_horse_with_no_name | 2014-02-22

Schreibe einen Kommentar