Tuesday, 15 June 2010

Querydsl vs JPA 2.0 Criteria API: First-round knockout

DISCLAIMER: I am not affiliated with the Querydsl team in any way, shape or form.

I've been developing with JPA on and off for a while now, only on small projects, but enough to be comfortable with it. 


Like everyone else, I soon reached the point where I thought "ergh, I don't much like embedding strings in my code to query my objects". @NamedQueries get checked a little, but not enough. I've been hit with build errors from my Hudson build server that my IDE (Eclipse, of course) doesn't notice and found the approach little better than embedding SQL strings. I'd also worked a little with LINQ in .NET and liked what I saw. I'm holding my breath for lambda functions in JDK 7, but to be honest, I'm feeling a bit light-headed and my face has gone purple.

So I came to the Criteria API that comes with JPA 2.0. Hey! That looks good. It's not LINQ, bit it looks like it'll do what I want. Typesafe queries. IDE code-completion. Nice. That's going to make my life easier and better.

Can you see where we are going readers? Yes? Yes. That's right. Then I tried to use it. OK "select p from Pet p" is easy. But it takes 5 lines of code. I have to create a CriteriaBuilder. Then a CriteriaQuery. Then a Root. Then a TypedQuery. Only then can I get the results. 

Now, let's be clear. I can write SQL. I'be been writing SQL for 15 years. I know how to write SQL to get the results I need in the majority of situations (and believe me, I've been tempted to do just that). My first non-trivial CriteriaQuery with the JPA Criteria API was to create a report joining a handful of tables, selecting a couple of attributes from each of those tables. I can do this with SQL. It's simple. I can't do it with the Criteria API. I'm NOT saying it's impossible. I'm sure it is possible. I'm sure it's easy, when you know how. But I don't know how, and for the life of me I can't find straightforward documentation or examples that explain clearly how to do this. So I leave it and go and do something else. Then I come back to it. What is that code? What does it mean? What does it do? I thought this was supposed to be better?

I didn't want to veer away from the standard API. I like standards. I prefer to work with APIs that are widely used, that have a common experience base. It makes life easier. But I kept seeing Querydsl (http://source.mysema.com/display/querydsl/Querydsl) mentioned. I think I'd noticed it before when looking into LINQ equivalents for Java. But  thought it looked a little too green for my taste, too much vaporware potential. So I kept away. But out of frustration, I came back. Hey! They have current activity. They have frequent releases. They have documentation... with examples. They have snippets for my POM (subliminalUSE MAVEN). The code ...looks...readable! I can understand at a glance what its doing! This can't be right. It won't work when I try it. 

So I try it. Hang on. It works! I can replace 5 opaque lines with 3 transparent ones! Let's try my report query... Wait... It's easy! I can read the code! It makes sense! It produces the SQL I expect! 

Ok. Job done. Criteria API in the bin. Querydsl in my holster. No contest. 

If you are using JPA and want to write typesafe queries in an IDE, then stop using the JPA 2.0 Criteria API and start using Querydsl. Today. 

If you work on the Criteria API team, get someone who's never used it to try to figure it out for themselves. Then, take them out for a beer and say sorry to them. Then hire the Querydsl team. 

P.S. Querydsl team - change the name. It's rubbish ;-)

5 comments:

Timo Westkämper said...

Thanks for the Querydsl promotion. Querydsl (spell: querydiesel) comes from Query-DSL, we thought it would be quite fitting. "Query", because it is the main domain, and "DSL" (domain specific language) because it is an internal DSL framework. Most Java-Query name variations are already used, and using something unrelated didn't seem too smart either. If you come up with something better, let us know! ;)

Bob Walker said...

Hi Timo - thanks for the info - and do excuse my flippancy - I appreciate it's not always easy to name stuff, and I don't see any better names either out there or in my head... If a name occurs to me I'll be sure to give you a shout. For now, I'm off to enjoy writing queries for the first time in ages....!

Timo Westkämper said...

Just to let you know, the new Querydsl site is at www.querydsl.com

Unknown said...

Hi,
Does this support databases such as DB2 and other prominent dbs'? How about code portability factor on different dbs'?

Thanks.

Unknown said...

hi doctor @timo, i have a problem with my queryDsL,
i have this assciation

@JsonIgnore
@OneToOne(fetch = FetchType.LAZY, orphanRemoval = false)
@JoinColumn(name = "location_id", insertable = false, updatable = false)
JPEventLocation location;


il my findAllOperation
i have this

@Override
protected Predicate toPredicate() {

QJPEvent event = QJPEvent.jPEvent;
if (locationId != null) {
predicate.and(event.location.id.eq(locationId));
}

ha have a cross join , any help