3

I am trying to run a query to fetch some statistic data from my database. And I'm using JPA. But I faced such a trouble: when I run JPQL query, the empty result set is returned. But when I run SQL, produced with JPA for that JPQL query, I got a single row of data.

Here's what I've got:

The Ticket entity

@Entity
@Table(name="tickets")
public class Ticket extends AbstractEntity {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    @Embedded
    private Owner owner;

    @ManyToOne
    @JoinColumn(name="flightId")
    private Flight flight;

    private String status;

    public Ticket() {
        this.status = "AVAILABLE";
    }

The Flight entity

@Entity
@Table(name="flights")
public class Flight extends AbstractEntity {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;

    private String departure;
    private String destination;
    private Date date;
    private float ticketCost;

    @OneToMany(mappedBy="flight", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    private List<Ticket> tickets = new ArrayList<Ticket>();

The result row class

public class SoldReportRow {
    private String departure;
    private String destination;
    private DateTime date;
    private int ticketsSold;
    private float totalCost;

    public SoldReportRow(Date date, String departure, String destination, Long ticketsSold, Double totalCost) {
        this.departure = departure;
        this.destination = destination;
        this.ticketsSold = ticketsSold.intValue();
        this.totalCost = totalCost.floatValue();
        this.date = new DateTime(date);
    }

The JPQL

SELECT NEW entities.SoldReportRow(f.date, f.departure, f.destination, 
    COUNT(t.id), SUM(f.ticketCost)) 
FROM  Ticket t JOIN t.flight f  
WHERE t.status = 'SOLD' AND t.owner IS NOT NULL AND f.date BETWEEN ? and ? 
GROUP BY f.id

The generated SQL

SELECT t0.DATE, t0.DEPARTURE, t0.DESTINATION, COUNT(t1.ID), SUM(t0.TICKETCOST) 
FROM flights t0, tickets t1 
WHERE ((((t1.STATUS = ?) AND NOT ((((((t1.ADDRESS IS NULL) 
    AND (t1.EMAIL IS NULL)) AND (t1.NAME IS NULL)) AND (t1.OWNERFROM IS NULL)) 
    AND (t1.PHONE IS NULL)))) AND (t0.DATE BETWEEN ? AND ?)) 
    AND (t0.ID = t1.flightId)) GROUP BY t0.ID

So here is what I got when I run JPQL:

JPQL gives an empty results' collection

And here is what I got when I run the generated SQL:

SQL gives a single row

UPD: the TicketDAO methods

// ...

protected static EntityManagerFactory factory;
protected static EntityManager em;

static {
    factory = Persistence.createEntityManagerFactory(UNIT_NAME);
}

// ...

public static List<SoldReportRow> soldReportByDate(String from, String to) {
    DateTimeFormatter dfTxt = DateTimeFormat.forPattern("dd/MM/yyyy");
    DateTimeFormatter dfSql = DateTimeFormat.forPattern("yyyy-MM-dd");

    String startDate = dfSql.print(dfTxt.parseDateTime(from));
    String endDate = dfSql.print(dfTxt.parseDateTime(to));

    String query = String.format(
            "SELECT NEW entities.SoldReportRow(f.date, f.departure, f.destination, COUNT(t.id), SUM(f.ticketCost)) FROM " +
            "Ticket t JOIN t.flight f " +
            "WHERE t.status = 'SOLD' AND t.owner IS NOT NULL AND f.date BETWEEN '%s' and '%s' " +
            "GROUP BY f.id",
            startDate, endDate
    );

    return TicketDAO.query(SoldReportRow.class, query);
}

public static <T> List<T> query(Class<T> entityClass, String query) {
    EntityManager entityManager = getEntityManager();
    TypedQuery<T> q = entityManager.createQuery(query, entityClass);
    List<T> entities = null;

    try {
        entities = q.getResultList();
    } finally {
        entityManager.close();
    }

    return entities;
}

public static EntityManager getEntityManager() {
    return factory.createEntityManager();
}

The question is, why does this happen and how to fix that?

Thanks!

13
  • The problem obviously comes from your query. Show whats inside the method TicketDAO.soldReportBy Commented Apr 8, 2014 at 22:29
  • @SujanSivagurunathan here you go! =) Commented Apr 8, 2014 at 22:34
  • Print the parameters's values before (or just after) passing them into the method , and lets us know what you have there already. No null reference, right ? Commented Apr 8, 2014 at 22:41
  • @SujanSivagurunathan dates are correct and are sprintf-ed right into a query. So the trouble is not there i think... Commented Apr 8, 2014 at 23:02
  • Print out the String query, you will see clearer. The problem might not come from there though. Did you try the getSingleResult method ? Commented Apr 8, 2014 at 23:08

1 Answer 1

3

After the research, I've found that the trouble was caused by the data at the database. By default, SQLite does not have the DATE column type. And it uses strings to describe timestamps. So for date comparison (just like SELECT ... WHERE date BETWEEN a AND b) it's better to use UTC date form, not string one (1397036688 is the better value than the 2014-03-09).

Sign up to request clarification or add additional context in comments.

1 Comment

Glad you found the problem. I never used SQLite, but guess it's good to know that there is no DATE column type by default in that DBMS. And yes its easier/faster to sort/compare numbers than a set of characters, so its better :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.