views:

1422

answers:

2

Hello there !

I'm trying to create a query with the Criteria API from JPA 2.0, but I can't make it work.

The problem is with the "between" conditional method. I read some documentation to know how I have to do it, but since I'm discovering JPA, I don't understand why it does not work.

First, I can't see "creationDate" which should appear when I write "Transaction_."

I thought it was maybe normal, since I read the metamodel was generated at runtime, so I tried to use 'Foo_.getDeclaredSingularAttribute("value")' instead of 'Foo_.value', but it still doesn't work at all.

Here is my code :

public List<Transaction> getTransactions(Date startDate, Date endDate) {
    EntityManager em = getEntityManager();
    try {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Transaction> cq = cb.createQuery(Transaction.class);
        Metamodel m = em.getMetamodel();
        EntityType<Transaction> Transaction_ = m.entity(Transaction.class);
        Root<Transaction> transaction = cq.from(Transaction.class);

        // Error here. cannot find symbol. symbol: variable creationDate
        cq.where(cb.between(transaction.get(Transaction_.creationDate), startDate, endDate));

        // I also tried this:
        // cq.where(cb.between(Transaction_.getDeclaredSingularAttribute("creationDate"), startDate, endDate));

        List<Transaction> result = em.createQuery(cq).getResultList();
        return result;
    } finally {
        em.close();
    }
}

Can someone help me to figure this out? Thanks.

EDIT : here is the Transaction source (almost nothing in it, since it was automatically generated by Netbeans, from my database)

package projetjava.db;

import java.io.Serializable;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "transaction")
@NamedQueries({
    @NamedQuery(name = "Transaction.findAll", query = "SELECT t FROM Transaction t"),
    @NamedQuery(name = "Transaction.findById", query = "SELECT t FROM Transaction t WHERE t.id = :id"),
    @NamedQuery(name = "Transaction.findByIDAccount", query = "SELECT t FROM Transaction t WHERE t.iDAccount = :iDAccount"),
    @NamedQuery(name = "Transaction.findByDescription", query = "SELECT t FROM Transaction t WHERE t.description = :description"),
    @NamedQuery(name = "Transaction.findByCreationDate", query = "SELECT t FROM Transaction t WHERE t.creationDate = :creationDate"),
    @NamedQuery(name = "Transaction.findByAmount", query = "SELECT t FROM Transaction t WHERE t.amount = :amount")})
public class Transaction implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "ID")
    private Integer id;
    @Basic(optional = false)
    @Column(name = "IDAccount")
    private int iDAccount;
    @Basic(optional = false)
    @Column(name = "Description")
    private String description;
    @Basic(optional = false)
    @Column(name = "CreationDate")
    @Temporal(TemporalType.DATE)
    private Date creationDate;
    @Basic(optional = false)
    @Column(name = "Amount")
    private double amount;

    public Transaction() {
    }

    public Transaction(Integer id) {
        this.id = id;
    }

    public Transaction(Integer id, int iDAccount, String description, Date creationDate, double amount) {
        this.id = id;
        this.iDAccount = iDAccount;
        this.description = description;
        this.creationDate = creationDate;
        this.amount = amount;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public int getIDAccount() {
        return iDAccount;
    }

    public void setIDAccount(int iDAccount) {
        this.iDAccount = iDAccount;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Transaction)) {
            return false;
        }
        Transaction other = (Transaction) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "projetjava.db.Transaction[id=" + id + "]";
    }

}
A: 

I think the confusing part here is q.where(cb.between(transaction.get(Transaction_.creationDate), startDate, endDate));

You must note that Transaction_ in this case is a static-instantiated, canonical metamodel class corresponding to the original Transaction entity class. You must generate Transaction_ class by compiling your Transaction class using JPA libraries. One useful link is here for eclipse: http://wiki.eclipse.org/UserGuide/JPA/Using_the_Canonical_Model_Generator_%28ELUG%29

For intellij IDEA

http://blogs.jetbrains.com/idea/2009/11/userfriendly-annotation-processing-support-jpa-20-metamodel/

ring bearer
Can I create `Transaction_` manually somewhere?
Pym
Now sure how you will hand-create the canonical metamodel.Are you using any IDE? if so follow applicable links or for eclipse, take a look at answer below.What version of Java are you using?An implicit understanding among JPA providers is that they'll generate metamodel using the annotation processor integrated in the Java 6 compiler.
ring bearer
+1  A: 

I thought it was maybe normal, since I read the metamodel was generated at runtime (...)

Metamodel classes are generated at compile time using annotation processing. In other words, you need to activate annotation processing at the compiler level. The Hibernate JPA 2 Metamodel Generator documentation describes how to do that with Ant, Maven and IDEs like Eclipse or Idea (the approach can be transposed to other providers). Sadly, this feature is currently not supported in NetBeans.

So either use and configure one of the mentioned build tool or switch to another IDE. For example, with Eclipse, right-click on the project and go to Java Compiler > Annotation Processing and Enable it:

alt text

Then add the required JAR(s) of your provider (refer to the documentation of your JPA provider for this step) to the Factory Path.

Pascal Thivent
Thanks! I also had a look at the Netbeans nightlies and it seems that they implemanted the same functionalities recently.
Pym
@Pym Good to know (I understood this would be available in NB 6.9 which has been recently released in Beta). Thanks for the feedback.
Pascal Thivent