Querydsl - Another LINQ for Java approach

49 views
Skip to first unread message

timowest

unread,
Nov 3, 2008, 2:16:26 PM11/3/08
to LINQ for Java
We have developed a framework called Querydsl (http://
source.mysema.com/projects/querydsl-root/) which like Thomas' JaQu,
provides the ability to write statically typed queries in native Java.

Here some examples from a test suite where we modeled Querydsl queries
after HQL (Hibernate) queries :

@Test
public void testWhere() throws Exception {
// parse( "FROM eg.mypackage.Cat qat where qat.name like
'%fluffy%' or qat.toes > 5" );
from(qat).where(qat.name.like("%fluffy
%").or(qat.toes.gt(5))).parse();
// parse( "FROM eg.mypackage.Cat qat where not qat.name like
'%fluffy%' or qat.toes > 5" );
from(qat).where(not(qat.name.like("%fluffy
%")).or(qat.toes.gt(5))).parse();
// parse( "FROM eg.mypackage.Cat qat where not qat.name not
like '%fluffy%'" );
from(qat).where(not(qat.name.like("%fluffy%"))).parse();
// parse( "FROM eg.mypackage.Cat qat where qat.name in
('crater','bean','fluffy')" );

from(qat).where(qat.name.in("crater","bean","fluffy")).parse();
// parse( "FROM eg.mypackage.Cat qat where qat.name not in
('crater','bean','fluffy')" );

from(qat).where(qat.name.notIn("crater","bean","fluffy")).parse();
// parse( "from Animal an where sqrt(an.bodyWeight)/2 > 10" );
from(an).where(div(sqrt(an.bodyWeight),2).gt(10)).parse();
// parse( "from Animal an where (an.bodyWeight > 10 and
an.bodyWeight < 100) or an.bodyWeight is null" );

from(an).where(an.bodyWeight.gt(10).and(an.bodyWeight.lt(100).or(an.bodyWeight.isnull()))).parse();
}


More examples : http://source.mysema.com/projects/querydsl-root/xref-test/com/mysema/query/grammar/hql/HqlParserTest.html

What do you think?

Br,
Timo Westkämper

Thomas Mueller

unread,
Nov 5, 2008, 2:13:46 PM11/5/08
to jl...@googlegroups.com
Hi,

> // from eg.DomesticCat cat where cat.name between 'A' and 'B'
> from(cat).where(cat.name.between("A", "B"));

The disadvantage is that 'name' can't be a String type, that means
it's not possible to use POJOs (plain old java objects). The advantage
is that the query looks better. Still there are some problems, for
example with AND / OR.

Regards,
Thomas

Kamil Demecki

unread,
Nov 6, 2008, 11:48:09 AM11/6/08
to LINQ for Java


On Nov 5, 8:13 pm, "Thomas Mueller" <thomas.tom.muel...@gmail.com>
wrote:
> Hi,
>
> > // from eg.DomesticCat cat where cat.name between 'A' and 'B'
> > from(cat).where(cat.name.between("A", "B"));
>
> The disadvantage is that 'name' can't be a String type, that means
> it's not possible to use POJOs (plain old java objects). The advantage
> is that the query looks better.


I think there is justification for addition abstraction on POJO.


like

@Entity
class Cat {
String name;
public static class ZpCat extedns ZpBase {
public Property name = createProperty(Cat.class, "name");
public static final ZpCat ZP = new ZpCat(Cat.class);
}
}

from(ZpCat.ZP).where(ZpCat.ZP.name.between("A", "B"));

So Cat is Pojo for model business which hold and operate on data and
ZpCat is for queries for Cat.

What are you thinking? ;>

>
> Regards,
> Thomas
> > More examples :http://source.mysema.com/projects/querydsl-root/xref-test/com/mysema/...

timowest

unread,
Nov 7, 2008, 2:58:34 AM11/7/08
to LINQ for Java

> I think there is justification for addition abstraction on POJO.
>
> like
>
> @Entity
> class Cat {
>   String name;
>   public static class ZpCat extedns ZpBase {
>      public Property name = createProperty(Cat.class, "name");
>      public static final ZpCat ZP = new ZpCat(Cat.class);
>   }
>
> }
>
> from(ZpCat.ZP).where(ZpCat.ZP.name.between("A", "B"));
>
> So Cat is Pojo for model business which hold and operate on data and
> ZpCat is for queries for Cat.
>
> What are you thinking? ;>

That's what we are doing. The domain model for the queries can be
easily auto-generated via APT.

Also using a prefix like Zp* is not necessary, you could use a
different package.

Here is an example from our test suite :

public static final class Department extends
Path.Entity<com.mysema.query.grammar.hql.HqlDomain.Department>{
public final Path.String name = _string("name");
public final Path.Comparable<java.lang.Integer> id =
_comparable("id",java.lang.Integer.class);
public final
Path.EntityList<com.mysema.query.grammar.hql.HqlDomain.Employee>
employees =
_entitylist("employees",com.mysema.query.grammar.hql.HqlDomain.Employee.class);
public Employee employees(int index) {
return new Employee(forListAccess(employees,index));
}
public Employee employees(Expr<Integer> index) {
return new Employee(forListAccess(employees,index));
}
public Company company;
public Company _company() {
if (company == null) company = new
Company(forProperty(this,"company"));
return company;
}
public Department(java.lang.String path) {

super(com.mysema.query.grammar.hql.HqlDomain.Department.class, path);
_company();
}
public Department(PathMetadata<?> metadata) {

super(com.mysema.query.grammar.hql.HqlDomain.Department.class,
metadata);
}
}

Kamil Demecki

unread,
Nov 7, 2008, 7:20:46 AM11/7/08
to LINQ for Java


On Nov 7, 8:58 am, timowest <timo.westkam...@gmail.com> wrote:
> > I think there is justification for addition abstraction on POJO.
>
> > like
>
> > @Entity
> > class Cat {
> >   String name;
> >   public static class ZpCat extedns ZpBase {
> >      public Property name = createProperty(Cat.class, "name");
> >      public static final ZpCat ZP = new ZpCat(Cat.class);
> >   }
>
> > }
>
> > from(ZpCat.ZP).where(ZpCat.ZP.name.between("A", "B"));
>
> > So Cat is Pojo for model business which hold and operate on data and
> > ZpCat is for queries for Cat.
>
> > What are you thinking? ;>
>
> That's what we are doing. The domain model for the queries can be
> easily auto-generated via APT.
>

I had seeing APT after posting ;>

I'm against slow down each build to run APT (in my case it is
important because build cycle is now to long). I think that better is
to take resposibility by programmer to run APT after change Model.
Certainly it is no problem

> Also using a prefix like Zp* is not necessary, you could use a
> different package.
>

Hm, Often you must build query and unpack parameters which tends to
using model *and* query parameters in the same class. This ends with
long declaration com.mysema.query.grammar.hql.HqlDomain.Department
which is ugly imho and lengthen code.

There is option to changee name of generated class with some filter ?

timowest

unread,
Nov 7, 2008, 11:12:51 AM11/7/08
to LINQ for Java
> I'm against slow down each build to run APT (in my case it is
> important because build cycle is now to long). I think that better is
> to take resposibility by programmer to run APT after change Model.
> Certainly it is no problem

Yes, both ways are possible. Using APT in sync with your compilation
slows down compilation but your queries and domain refactorings in
sync.

For a slow machine, explicit APT runs are probably better.


>Hm, Often you must build query and unpack parameters which tends to
>using model *and* query parameters in the same class. This ends with
>long declaration com.mysema.query.grammar.hql.HqlDomain.Department
>which is ugly imho and lengthen code.

We are referring to the real domain types via fully qualified class
names, since otherwise there would be name clashes with the local
domain types. We try to focus on compact and safe autogenerated code.


> There is option to changee name of generated class with some filter ?

Yes, it is declared via the following APT parameter :

-AdestClass=com.mysema.query.Domain1,

Currently the implementation creates inner classes for the given
destination class, but this can be easily customized, if wanted.

Kamil Demecki

unread,
Nov 12, 2008, 11:03:13 AM11/12/08
to LINQ for Java


On Nov 7, 5:12 pm, timowest <timo.westkam...@gmail.com> wrote:
>
> >Hm, Often you must build query and unpack parameters which tends to
> >using model *and* query parameters in the same class. This ends with
> >long declaration com.mysema.query.grammar.hql.HqlDomain.Department
> >which is ugly imho and lengthen code.
>
> We are referring to the real domain types via fully qualified class
> names, since otherwise there would be name clashes with the local
> domain types. We try to focus on compact and safe autogenerated code.
>

I think full qualified names are for compilers/parsers. For
programmers not qualified and unique name is better. Is has been
proved for me. Hit C-O in Eclipse and make camel search with unique
name. Other point is my system has long packages, so unique names are
more important.

In mid size systems there are 200-1000 entities (enity has suffiks OB
and other classes are others prefix/suffiks like DAO, Action, View)
which occurs in groups so I thinks name pool for system expand well
without need to fully qualified names ;> Imho it is requiremt ;>


> > There is option to changee name of generated class with some filter ?
>
> Yes, it is declared via the following APT parameter :
>
>   -AdestClass=com.mysema.query.Domain1,

So I will have to give one parametrer per one entity ? With 200
entities are needed 200 parameters and 200 run apt ? ;>

There is no something like pattern ?

>
> Currently the implementation creates inner classes for the given
> destination class, but this can be easily customized, if wanted.


Old-Good OpenSource ;> Off course with good desing ;>

timowest

unread,
Nov 12, 2008, 11:42:10 AM11/12/08
to LINQ for Java


On Nov 12, 6:03 pm, Kamil Demecki <skajo...@gmail.com> wrote:
> On Nov 7, 5:12 pm, timowest <timo.westkam...@gmail.com> wrote:
>
>
>
> > >Hm, Often you must build query and unpack parameters which tends to
> > >using model *and* query parameters in the same class. This ends with
> > >long declaration com.mysema.query.grammar.hql.HqlDomain.Department
> > >which is ugly imho and lengthen code.
>
> > We are referring to the real domain types via fully qualified class
> > names, since otherwise there would be name clashes with the local
> > domain types. We try to focus on compact and safe autogenerated code.
>
> I think full qualified names are for compilers/parsers. For
> programmers not qualified and unique name is better. Is has been
> proved for me. Hit C-O in Eclipse and make camel search with unique
> name. Other point is my system has long packages, so unique names are
> more important.

Ok. We could add an option for a prefix to the simple name of the
generated class.

>
> In mid size systems there are 200-1000 entities (enity has suffiks OB
> and other classes are others prefix/suffiks like DAO, Action, View)
> which occurs in groups so I thinks name pool for system expand well
> without need to fully qualified names ;> Imho it is requiremt ;>
>
> > > There is option to changee name of generated class with some filter ?
>
> > Yes, it is declared via the following APT parameter :
>
> >   -AdestClass=com.mysema.query.Domain1,
>
> So I will have to give one parametrer per one entity ? With 200
> entities are needed 200 parameters and 200 run apt ? ;>

No. All the generated classes are generated as inner classes of the
given domain type. But I could add an option to generate the classes
into a package.

>
> There is no something like pattern ?
>
>
>
> > Currently the implementation creates inner classes for the given
> > destination class, but this can be easily customized, if wanted.
>
> Old-Good OpenSource ;> Off course with good desing ;>

Yes, like I said.

So basically you would like to

* control the prefix of the generated class :
e.g. somepackage.Cat -> someotherpackage.ZpCat

* generate the classes into a package instead of using inner classes


I will try to add these options soon. Anything else? All comments are
most welcome.

Kamil Demecki

unread,
Nov 13, 2008, 6:09:39 AM11/13/08
to LINQ for Java
Great ;>

Generating inner class inside entity (one generated per one entity) is
possible ? (like below ZpCat with default static access ZpCat.ZP)

@Entity
class Cat {
String name;
public static class ZpCat extedns ZpBase {
public Property name = createProperty(Cat.class, "name");
public static final ZpCat ZP = new ZpCat(Cat.class);
}
}

In my project generating will be on demand, so whole entity Cat will
be versioned in svn also with generated part. I will plan write this
code by hand but I won't have to with your great framework ;>

I think Static access should be default because usually there are
10-30 services which query entity and it is wasting cpu to create
objects like this per method invoking.

timowest

unread,
Nov 16, 2008, 9:33:44 AM11/16/08
to LINQ for Java
Hi Kamil.

We just released querydsl version 0.2.8 with the following APT
options :

* destClass : destination class for query domain types (inner
class switch)
* destPackage : destination package for query domain types (outer
class switch)
* dtoClass : destination class for query DTO types (inner class
switch)
* dtoPackage : destination package for query DTO types (outer
class switch)
* include : file path for class content of destClass
* namePrefix : prefix for query domain type simplenames

So for example if you want to generate classes into the package
com.foo with the prefix for the classes Bar the options would

-AdestPackage=com.foo, -AnamePrefix=Bar

Currently this takes only Hibernate classes into account
(javax.persistence.Entity annotated types). Do you need customization
for that? It is easily done ;)

A full-scale Maven example is available here :
https://source.mysema.com/svn/mysema/projects/querydsl/trunk/querydsl-hql/pom.xml

Hope this helps.

Br,
Timo Westkämper.

Kamil Demecki

unread,
Nov 17, 2008, 5:34:08 AM11/17/08
to LINQ for Java
Thanks. I will find time to run and feedback, I hope in this week ;>

On Nov 16, 3:33 pm, timowest <timo.westkam...@gmail.com> wrote:
> Hi Kamil.
>
> We just released querydsl version 0.2.8 with the following APT
> options :
>
>     * destClass : destination class for query domain types (inner
> class switch)
>     * destPackage : destination package for query domain types (outer
> class switch)
>     * dtoClass : destination class for query DTO types (inner class
> switch)
>     * dtoPackage : destination package for query DTO types (outer
> class switch)
>     * include : file path for class content of destClass
>     * namePrefix : prefix for query domain type simplenames
>
> So for example if you want to generate classes into the package
> com.foo with the prefix for the classes Bar the options would
>
>    -AdestPackage=com.foo, -AnamePrefix=Bar
>
> Currently this takes only Hibernate classes into account
> (javax.persistence.Entity annotated types). Do you need customization
> for that? It is easily done ;)
>
> A full-scale Maven example is available here :https://source.mysema.com/svn/mysema/projects/querydsl/trunk/querydsl...

timowest

unread,
Dec 1, 2008, 5:35:55 AM12/1/08
to LINQ for Java
Querydsl bugs are now tracked on Launchpad : https://bugs.launchpad.net/querydsl

Feel free to participate.

timowest

unread,
Jan 20, 2009, 7:54:57 AM1/20/09
to LINQ for Java
Querydsl has matured and is now able to execute queries on top of
- JPA / Hibernate backends
- JDBC / SQL backends
- Java Bean based collections and lists

Feel free to check out the improvements on http://source.mysema.com/display/querydsl/Querydsl

Querydsl maven artifacts are now available on ibiblio.

Reply all
Reply to author
Forward
0 new messages