2011-03-16

Julkinen data seminaari - To 7.4.2011, Helsinki

Hallitus on tehnyt periaatepäätöksen (3.3.2011) julkishallinnon digitaalisten tietoaineistojen saatavuudesta. Tietoaineistojen tulee olla avoimesti saatavilla ja uudelleenkäytettävissä yhtenäisin, selkein ja kaikille tasapuolisin ehdoin. Periaatepäätös koskee ensisijaisesti sellaisenaan luovutettavissa olevia julkisia aineistoja, joiden käsittelyä ei lainsäädäntö rajoita.

Mutta mitä se tarkoittaa käytännössä? Miten julkisia tietoaineistoja tarjotaan?

Julkinen data seminaari torstaina 7.4.2011 Aalto yliopiston Chydenina-talossa Helsingissä tarjoaa tietoa julkisten tietovarantojen avaamiseen liittyen eri näkökulmilta. Seminaari on tarkoitettu kaikille tiedon parissa työskenteleville asiantuntijoille ja päättäjille kuntien ja valtion tehtävissä.

Tilaisuudessa esitellään:

  • mitä Julkinen data on
  • miten valtion periaatepäätöksellä pyritään edistämään julkisen hallinnon tietovarantojen saatavuutta ja käyttöä.
  • konkreettisia esimerkkejä mitä avoimilla tietovarantojen avulla on saatu aikaiseksi meillä ja maailmalla.
  • Case Helsingin kaupungin aluesarjat-tilastotietojen avaaminen ja teknisen ratkaisun rakentaminen

Tilaisuuden ohjelma:

8:30 Rekisteröityminen ja aamukahvit

9:00 Avaus - missä mennään julkisten tietovarantojen avauksessa, Taru Rastas, Liikenne ja Viestintäministeriö

9:15 Julkinen data - mitä kaikkea se onkaan? Tapio Nurminen, FloApps Oy

10:00 Kahvitauko

10:15 Case esittely - Aluesarjat-tilastot avoimeksi, Pekka Vuori, Yliaktuaari, Helsingin Kaupungin Tietokeskus

10:45 Q&A + Aluesarjat Demot by FloApps & Mysema

11.30 Lounas

12.30 Julkista dataa hyödyntäviä esimerkkisovelluksia ja -palveluita Suomessa ja maailmalla. Tapio Nurminen, Toimitusjohtaja, FloApps Oy

13:00 Datan avaaminen käytännössä-teknisen ratkaisun rakentaminen, Samppa Saarela, Mysema Oy

13:30 Avoin tieto laadukkaaksi data managementin avulla, Nino Ilveskero, Talent Base Oy

14:00 Kahvitauko

14:15 Liiketoimintamallit julkisen datan avulla, Juho Lindman, Aalto Econ. CKIR

14:45-15:30 Yhteenveto + kysymykset - Tapio Nurminen ja Samppa Saarela

Tilaisuuden hinta on 75 € + alv. 23%

Ilmoittaudu ystävällisesti tilaisuuteen 25.3. mennessä kahvi- ja lounasjärjestelyjen johdosta ennakkoon osoitteessa:

http://bit.ly/h9Hk0K

Seminaari järjestetään: torstaina 7. huhtikuuta, klo 8.30 - 15.30 Aalto-Yliopiston Chydenia-talossa osoitteessa Runeberginkatu 22-24, Helsinki.

Järjestäjät ovat Flo Apps Oy ja Mysema Oy,
yhteistyössä Helsinki Regional Infoshare, Aalto Yliopiston Econ. osaston ja Talent Base Oy:n kanssa.

2011-01-21

Querying in SQL with Querydsl

Querydsl provides a typesafe querying layer on top of JPA, JDO, JDBC and other backends. This blog post presents a simple tutorial on how to get started with querying in SQL using Querydsl.

Querydsl for SQL provides a typesafe view of the relational schema and makes expressing database queries in Java as intuitive as possible.

Getting started


To get started with Querydsl for SQL using a Maven 2 based build environment, follow these steps.

Add the following dependencies to your Maven project and make sure that the Maven 2 repo of Mysema Source is accessible from your POM :

<dependency>
  <groupId>com.mysema.querydsl</groupId>
  <artifactId>querydsl-sql</artifactId>
  <version>${querydsl.version}</version>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.6.1</version>
</dependency>   

The snippet to include the Mysema Source Maven repository is :

<repository>
  <id>msource</id>
  <url>http://source.mysema.com/maven2/releases/</url>
  <releases>
    <enabled>true</enabled>
  </releases>
  <snapshots>
    <enabled>false</enabled>
  </snapshots>
</repository>

Set the variable querydsl.version to the latest Querydsl version available.

If you are not using Maven you can download the latest builds from here

Creating the Querydsl query types


To get started with creating Querydsl SQL queries you need to create Java classes for your relational schema. This can be done either in Java, via Maven or via Ant.

In Java


To get started export your schema into Querydsl query types like this :

java.sql.Connection conn = ...; 
MetaDataExporter exporter = new MetaDataExporter();
exporter.setPackageName("com.myproject.mydomain");
exporter.setTargetFolder(new File("src/main/java"));
exporter.export(conn.getMetaData());  

This declares that the database schema is to be mirrored into the com.myproject.domain package in the src/main/java folder.

The generated types have the table name transformed to mixed case as the class name and a similar mixed case transformation applied to the columns which are available as property paths in the query type.

In Maven


This functionality is also available as a Maven plugin. The presented example can be declared like this in the POM :

<plugin>
  <groupId>com.mysema.querydsl</groupId>
  <artifactId>querydsl-maven-plugin</artifactId>
  <version>${querydsl.version}</version>
  <executions>
    <execution>
      <goals>
        <goal>export</goal>
      </goals>
    </execution>            
  </executions>
  <configuration>
    <jdbcDriver>org.apache.derby.jdbc.EmbeddedDriver</jdbcDriver>
    <jdbcUrl>jdbc:derby:target/demoDB;create=true</jdbcUrl>
    <packageName>com.myproject.domain</packageName>
    <targetFolder>${project.basedir}/target/generated-sources/java</targetFolder> 
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.apache.derby</groupId>
      <artifactId>derby</artifactId>
      <version>${derby.version}</version>
    </dependency>
  </dependencies>
</plugin>  

Use the goal test-export to add the targetFolder as a test compile source root instead of a compile source root.

In ANT


The ANT task com.mysema.query.sql.ant.AntMetaDataExporter of the querydsl-sql module provides the same functionality as an ANT task. The configuration parameters of the task are jdbcDriverClass, dbUrl, dbUserName, dbPassword, namePrefix, targetPackage, targetSourceFolder, schemaPattern, tableNamePattern, exportBeans and innerClassesForKeys.

Using query types


To create queries with Querydsl you need to instantiate variables and Query implementations. We will start with the variables.

For each table in your mirrored schema a query type is created. For example for the table customer Querydsl will generate a query type with the simple name QCustomer into the folder and package declared in the code generation setup. QCustomer can be used as a statically typed variable in Querydsl queries as a representative for the customer table.

QCustomer has a default instance variable which can be accessed as a static field :

QCustomer customer = QCustomer.customer;

Alternatively you can define your own QCustomer instances like this :

QCustomer customer = new QCustomer("c");


Querying


Querying with Querydsl SQL is as simple as this :

QCustomer customer = new QCustomer("c"); // alias for the CUSTOMER table

SQLTemplates dialect = new HSQLDBTemplates(); // SQL-dialect
SQLQuery query = new SQLQueryImpl(connection, dialect); 
List<String> lastNames = query.from(customer)
    .where(customer.firstName.eq("Bob"))
    .list(customer.lastName);

which is transformed into the following sql query, assuming that the related table name is customer and the columns first_name and last_name :

SELECT c.last_name 
FROM customer c 
WHERE c.first_name = 'Bob'

Internally Querydsl SQL uses prepared statements.

General usage


Use the the cascading methods of the com.mysema.query.sql.SQLQuery interface like this

from : Define the query sources here.

innerJoin, join, leftJoin, fullJoin, on : Define join elements using these constructs. For the join methods the first argument is the join source and the second the target (alias).

where : Define the query filters, either in varargs form separated via commas or cascaded via the and-operator.

groupBy : Define the group by arguments in varargs form.

having : Define the having filter of the "group by" grouping as an varags array of Predicate expressions.

orderBy : Define the ordering of the result as an varargs array of order expressions. Use asc() and desc() on numeric, string and other comparable expression to access the OrderSpecifier instances.

limit, offset, restrict : Define the paging of the result. Limit for max results, offset for skipping rows and restrict for defining both in one call.

Ordering


The syntax for declaring ordering is

query.from(customer)
    .orderBy(customer.lastName.asc(), customer.firstName.asc())
    .list(customer.firstName, customer.lastName);

which is equivalent to the following native SQL

SELECT c.first_name, c.last_name
FROM customer c 
ORDER BY c.last_name ASC, c.first_name ASC

Grouping


Grouping can be done in the following form

query.from(customer)
    .groupBy(customer.lastName)
    .list(customer.lastName);

which is equivalent to the following native SQL

SELECT c.last_name 
FROM customer c 
GROUP BY c.last_name

Subqueries


To create a subquery you create a com.mysema.query.sql.SQLSubQuery instance, define the query parameters via from, where etc and use unique or list to create a subquery, which is just a type-safe Querydsl expression for the query. unique is used for a unique (single) result and list for a list result.

query.from(customer).where(
  customer.status.eq(new SQLSubQuery().from(customer2).unique(customer2.status.max()))
  .list(customer.all())

Another example

query.from(customer).where(
  customer.status.in(new SQLSubQuery().from(status).where(status.level.lt(3)).list(status.id))
  .list(customer.all())

Query extension support


Custom query extensions to support engine specific syntax can be created by subclassing com.mysema.query.sql.AbstractSQLQuery and adding flagging methods like in the given MySQLQuery example :

public class MySQLQuery extends AbstractSQLQuery<MySQLQuery>{
    
    public MySQLQuery(Connection conn) {
        this(conn, new MySQLTemplates(), new DefaultQueryMetadata());
    }
    
    public MySQLQuery(Connection conn, SQLTemplates templates) {
        this(conn, templates, new DefaultQueryMetadata());
    }
    
    protected MySQLQuery(Connection conn, SQLTemplates templates, QueryMetadata metadata) {
        super(conn, new Configuration(templates), metadata);
    }
    
    public MySQLQuery bigResult(){
        return addFlag(Position.AFTER_SELECT, "SQL_BIG_RESULT ");
    }
    
    public MySQLQuery bufferResult(){
        return addFlag(Position.AFTER_SELECT, "SQL_BUFFER_RESULT ");
    }
 
 
    // ...   
}        


The flags are custom SQL snippets that can be inserted at specific points in the serialization. The supported positions are the enums of the com.mysema.query.QueryFlag.Position enum class.

Using DDL commands


CREATE TABLE commands can be used in fluent form via the com.mysema.query.sql.ddl.CreateTableClause class. Here are some examples :

new CreateTableClause(conn, templates, "language")
 .column("id", Integer.class).notNull()
 .column("text", String.class).size(256).notNull()
 .primaryKey("PK_LANGUAGE","id")
 .execute();

new CreateTableClause(conn, templates, "symbol")
 .column("id", Long.class).notNull()
 .column("lexical", String.class).size(1024).notNull()
 .column("datatype", Long.class)
 .column("lang", Integer.class)
 .column("intval",Long.class)
 .column("floatval",Double.class)
 .column("datetimeval",Timestamp.class)
 .primaryKey("PK_SYMBOL","id")
 .foreignKey("FK_LANG","lang").references("language","id")
 .execute();

new CreateTableClause(conn, templates, "statement")
 .column("model", Long.class)
 .column("subject", Long.class).notNull()
 .column("predicate", Long.class).notNull()
 .column("object", Long.class).notNull()
 .foreignKey("FK_MODEL","model").references("symbol","id")
 .foreignKey("FK_SUBJECT","subject").references("symbol","id")
 .foreignKey("FK_PREDICATE","predicate").references("symbol","id")
 .foreignKey("FK_OBJECT","object").references("symbol","id")
 .execute();    

The constructor of CreateTableClause takes the connection, the templates and the table name. The rest is declared via column, primaryKey and foreignKey invocations.

Here are the corresponding CREATE TABLE clauses as they are executed.

CREATE TABLE language (
  id INTEGER NOT NULL,
  text VARCHAR(256) NOT NULL,
  CONSTRAINT PK_LANGUAGE PRIMARY KEY(id)
)

 CREATE TABLE symbol (
  id BIGINT NOT NULL,
  lexical VARCHAR(1024) NOT NULL,
  datatype BIGINT,
  lang INTEGER,
  intval BIGINT,
  floatval DOUBLE,
  datetimeval TIMESTAMP,
  CONSTRAINT PK_SYMBOL PRIMARY KEY(id),
  CONSTRAINT FK_LANG FOREIGN KEY(lang) REFERENCES language(id)
)

 CREATE TABLE statement (
  model BIGINT,
  subject BIGINT NOT NULL,
  predicate BIGINT NOT NULL,
  object BIGINT NOT NULL,
  CONSTRAINT FK_MODEL FOREIGN KEY(model) REFERENCES symbol(id),
  CONSTRAINT FK_SUBJECT FOREIGN KEY(subject) REFERENCES symbol(id),
  CONSTRAINT FK_PREDICATE FOREIGN KEY(predicate) REFERENCES symbol(id),
  CONSTRAINT FK_OBJECT FOREIGN KEY(object) REFERENCES symbol(id)
)  

Using DML commands


All the com.mysema.query.dml.DMLClause implementations in the Querydsl SQL module take three parameters, the java.sql.Connection instance, the com.mysema.query.sql.SQLTemplates instance used in the queries and the main entity the DMLClause is bound to.

Insert examples :

// with columns
new SQLInsertClause(conn, dialect, survey)
    .columns(survey.id, survey.name)
    .values(3, "Hello").execute();

// without columns
new SQLInsertClause(conn, dialect, survey)
    .values(4, "Hello").execute();

// with subquery
new SQLInsertClause(conn, dialect, survey)
    .columns(survey.id, survey.name)
    .select(new SQLSubQuery().from(survey2).list(survey2.id.add(1), survey2.name))
    .execute();

// with subquery, without columns
new SQLInsertClause(conn, dialect, survey)
    .select(new SQLSubQuery().from(survey2).list(survey2.id.add(10), survey2.name))
    .execute();

Update examples :

// update with where
new SQLUpdateClause(conn, dialect, survey)
    .where(survey.name.eq("XXX"))
    .set(survey.name, "S")
    .execute();
  
// update without where
new SQLUpdateClause(conn, dialect, survey)
    .set(survey.name, "S")
    .execute()  

Delete examples :

// delete with where
new SQLDelecteClause(conn, dialect, survey)
    .where(survey.name.eq("XXX"))
    .execute();
  
// delete without where
new SQLDelecteClause(conn, dialect, survey)
    .execute()  

Bean class generation


To create JavaBean DTO types for the tables of your schema use the com.mysema.query.sql.MetaDataExporter like this :

java.sql.Connection conn = ...; 
MetaDataExporter exporter = new MetaDataExporter();
exporter.setPackageName("com.myproject.mydomain");
exporter.setTargetFolder(new File("src/main/java"));       
exporter.setBeanSerializer(new BeanSerializer());
exporter.export(conn.getMetaData());  

Now you can use the bean types as arguments to the populate method in DML clauses and you can project directly to bean types in queries. Here is a simple example :

@Test
QEmployee e = new QEmployee("e");
           
// Insert
Employee employee = new Employee();
employee.setFirstname("John");
Integer id = insert(e).populate(employee).executeWithKey(e.id);
employee.setId(id);

// Update
employee.setLastname("Smith");
assertEquals(1l, update(e).populate(employee).where(e.id.eq(employee.getId())).execute());

// Query
Employee smith = query().from(e).where(e.lastname.eq("Smith")).uniqueResult(e);
assertEquals("John", smith.getFirstname());
        
// Delete 
assertEquals(1l, delete(e).where(e.id.eq(employee.getId())).execute());

Where to go next


See the related section of the latest Reference docs for more information.

2010-11-10

MongoDB with Querydsl

Querydsl provides a typesafe querying layer on top of JPA, JDO, JDBC and other backends. This blog post presents a simple tutorial on how to get started with querying on MongoDB using Querydsl.

Maven integration


To get started with Querydsl for MongoDB using a Maven 2 based build environment, follow the following steps.

Add the following dependencies to your Maven project and make sure that the Maven 2 repo of Mysema Source is accessible from your POM :

<dependency>
  <groupId>com.mysema.querydsl</groupId>
  <artifactId>querydsl-mongodb</artifactId>
  <version>${querydsl.version}</version>
</dependency>

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.6.1</version>
</dependency>   

Querydsl uses the Annotation Processing Tool of Java 6 for code generation which needs to be configured as well :

<project>
  <build>
  <plugins>
    ...
    <plugin>
      <groupId>com.mysema.maven</groupId>
      <artifactId>maven-apt-plugin</artifactId>
      <version>1.0</version>
      <executions>
        <execution>
          <goals>
            <goal>process</goal>
          </goals>
          <configuration>
            <outputDirectory>${generatedSources}<outputDirectory>
            <processor>com.mysema.query.mongodb.morphia.MorphiaAnnotationProcessor</processor>
          </configuration>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
  </build>
</project>

The MorphiaAnnotationProcessor finds domain types annotated with the com.google.code.morphia.annotations.Entity and com.google.code.morphia.annotations.Embedded annotations and generates query types for them.

Run clean install and you will get your Query types generated into target/generated-sources/java.

If you use Eclipse, run mvn eclipse:eclipse to update your Eclipse project to include target/generated-sources/java as a source folder.

Now you are able to construct Querydsl query instances and instances of the query domain model.


Ant integration


If you have an Ant based build environment you can use one of the packaged releases from the Downloads page.

Place the jar files from the full-deps bundle on your classpath and use the following tasks for Querydsl code generation :

<!-- APT based code generation -->
   <javac srcdir="${src}" classpathref="cp">
     <compilerarg value="-proc:only"/>      
     <compilerarg value="-processor"/>
     <compilerarg value="com.mysema.query.mongodb.morphia.MorphiaAnnotationProcessor"/>
     <compilerarg value="-s"/>
     <compilerarg value="${generated}"/>
   </javac>
    
   <!-- compilation -->
   <javac classpathref="cp" destdir="${build}">      
     <src path="${src}"/>
     <src path="${generated}"/>
   </javac> 

Replace src with your main source folder, generated with your folder for generated sources and build with your target folder.

Using query types


To create queries with Querydsl you need to instantiate variables and Query implementations. We will start with the variables.

Let's assume that your project has the following domain type :

@Entity
public class Customer {

    private @Id ObjectId id;

    private String firstName;
    
    private String lastName;

    public String getFirstName(){
        return firstName;
    }

    public String getLastName(){
        return lastName;
    }

    public void setFirstName(String fn){
        firstName = fn;
    }

    public void setLastName(String ln)[
        lastName = ln;
    }

    public ObjectId getId() {
        return id;
    }

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

Querydsl will generate a query type with the simple name QCustomer into the same package as Customer. QCustomer can be used as a statically typed variable in Querydsl queries as a representative for the Customer type.

QCustomer has a default instance variable which can be accessed as a static field :

QCustomer customer = QCustomer.customer;

Alternatively you can define your own Customer variables like this :

QCustomer customer = new QCustomer("myCustomer");

Querying


For the MongoDB-module MorphiaQuery is the main Query implementation. It is instantiated like this :

// test database
String dbname = "testdb"; 
// Morphia configuration
Morphia morphia = new Morphia().map(Customer.class); 
// datastore
Datastore ds = morphia.createDatastore(dbname); 
QCustomer customer = QCustomer.customer;
MorphiaQuery<Customer> query = new MorphiaQuery<Customer>(morphia, ds, customer);

To retrieve the customer with the first name Bob you would construct a query like this :

QCustomer customer = QCustomer.customer;
MorphiaQuery<Customer> query = new MorphiaQuery<Customer>(morphia, ds, customer);
Customer bob = query.where(customer.firstName.eq("Bob"))
  .uniqueResult();

The where part defines the filter and uniqueResult tells Querydsl to return a single element. Easy, right?

And to use multiple filters use it like this

query
    .where(customer.firstName.eq("Bob"), customer.lastName.eq("Wilson"));   

Or like this

query
    .where(
      customer.firstName.eq("Bob").and(customer.lastName.eq("Wilson")));


General usage


Use the the cascading methods of the MorphiaQuery class like this

  • where : Define the query filters, either in varargs form separated via commas or cascaded via the and-operator.
  • orderBy : Define the ordering of the result as an varargs array of order expressions. Use asc() and desc() on numeric, string and other comparable expression to access the OrderSpecifier instances.
  • limit, offset, restrict : Define the paging of the result. Limit for max results, offset for skipping rows and restrict for defining both in one call.

Ordering


The syntax for declaring ordering is

query
    .orderBy(customer.lastName.asc(), customer.firstName.desc())
    .list();


Where to go next


For an up-to-date guide on how to use Querydsl with MongoDB, see the latest Reference Documentation.

And if you have any issues, questions or ideas for enhancement post a thread in the Mysema Source Forum.

Happy querying!

2010-10-04

SQL queries in Scala

In a previous blog post I showed you how Querydsl and Scala works with JPA, JDO and Mongodb. This blog post shows you how to use Scala queries on top of Querydsl SQL.

If you are using Maven you need the following two dependencies :

<dependency>
      <groupId>com.mysema.querydsl</groupId>
      <artifactId>querydsl-scala</artifactId>
      <version>${querydsl.version}</version>
</dependency>

<dependency>
      <groupId>com.mysema.querydsl</groupId>
      <artifactId>querydsl-sql</artifactId>
      <version>${querydsl.version}</version>
</dependency>

Like with Querydsl SQL for Java you need to generate Query types to be able to construct your queries. The following two unit test methods show how this is done :

val templates = new HSQLDBTemplates()
  var connection: Connection = _

  @Before
  def setUp() {
    // set up the JDBC connection for JDBC metadata access
    Class.forName("org.hsqldb.jdbcDriver")
    val url = "jdbc:hsqldb:mem:testdb"
    connection = DriverManager.getConnection(url, "sa", "")
  }

  @Test
  def Generation_without_Beantypes() {
    val namingStrategy = new DefaultNamingStrategy()
    val serializer = new ScalaMetaDataSerializer("Q", namingStrategy)
    val exporter = new MetaDataExporter("Q", "test", new File("target/gen1"), namingStrategy, serializer)
    exporter.setCreateScalaSources(true)
    exporter.export(connection.getMetaData())
  }

  @Test
  def Generation_with_Beantypes() {
    val namingStrategy = new DefaultNamingStrategy()
    val serializer = new ScalaMetaDataSerializer("Q", namingStrategy)
    val beanSerializer = new ScalaBeanSerializer()
    val exporter = new MetaDataExporter("Q", "com.mysema.example", new File("target/gen2"), namingStrategy, serializer, beanSerializer)
    exporter.setCreateScalaSources(true)
    exporter.export(connection.getMetaData())
  }

The MetaDataExporter can be used with and without Bean type generation. If you just want to write SQL queries and you don't need a JavaBean based model for projection, insertion and update, you can use it without bean projection. If you want to mirror your SQL schema into a minimal domain model and use it ORM-like then generate the bean types.

Make sure that the target folder (target/gen1 and target/gen2 in the two examples) is in your source path. And replace com.mysema.example with a target package of your choice.

Now you can use the generated query types for querying :

@Test
  def Querying() {
    val survey = new QSurvey("survey")
    val employee = new QEmployee("employee")

    assertEquals("abc", query from survey where (survey.id eq 1) 
      .uniqueResult survey.name)

    assertEquals("def", query from survey where (survey.id eq 2) 
      .uniqueResult survey.name)

    assertEquals("Bob", query from employee 
      .where (employee.lastname eq "Smith") 
      .uniqueResult employee.firstname)

    assertEquals("John", query from employee 
      .where (employee.lastname eq "Doe") 
      .uniqueResult employee.firstname)
  }

  def query = new SQLQueryImpl(connection, templates)

Querydsl SQL for Scala doesn't use the $-sign based escape syntax for expression construction nor alias variables. Instead code generation is used to output the Query model as a set of Scala classes that reflect the tables, columns and keys of your relational schema.

You can instantiate the generated Q-types instead. Alternatively you can also use a more SQL-like syntax:

val survey = QSurvey as "survey"

For more details on how to use Querydsl SQL see the related section in the latest revision of the Reference Documentation.

Recent released have changed the Querydsl Scala API. Visit the Reference Documentation for updated documentation.

2010-10-01

Using Querydsl In Eclipse

Querydsl usage in Eclipse is now easier than ever. Since Querydsl 2.0 we have improved APT support in Querydsl to support incremental code generation in IDEs. We have also improved the release bundles to streamline the APT configuration in Java IDEs like Eclipse.

The APT usage improvements affect the JPA, JDO and MongoDB modules. Instead of a set of screenshots we have prepared a screencast to showcase the new APT features in Querydsl in an Eclipse context.

To enable APT usage in Eclipse you need to
  • set the Enable annotation processing checkbox via Properties > Java Compiler > Annotation Processing,
  • add the APT option defaultOverwrite = true if you are using Eclipse Helios and
  • set the Factory Path to one of the apt-one-jar files included in your release bundle.

The screencast uses the Querydsl JPA module in combination with Hibernate and shows the creation of a Java project, the creation of two simple domain types and the creation of a minimal demo service which presents the simplicity of Querydsl query usage.

2010-09-28

Querydsl 2.0 has been released!

Querydsl 2.0 has been released! After two alpha and two beta releases we are proud to announce the final 2.0 release. The biggest single change in Querydsl 2.0 compared to previous 1.* releases is the improved Expression API. We got rid of the coupling between the query construction contract and the DSL features of the Expression API.

The Expression API is now divided into two parts, an interface based part which describes the archetypes of Expressions which are used in Query construction, and a class based part, which provides the standard Expression DSL.

Here is an UML overview of the new Expression model : Expression model changes

In addition to the improvements of the Expression API there is improved Eclipse IDE support, initial Scala and Mongodb support.

Querying with Scala

Scala support for Querydsl has been on the roadmap for some time, and with the Querydsl 2.0 release we got initial support for using Querydsl in Scala applications released.

The goal was to use the Query interfaces as such, and to provide an alternative expression DSL better suited for Scala usage. With most Querydsl modules APT is used for code generation. As there is no equivalent for Scala we didn't try to provide code generation features for Scala domain models.

Instead we combined the Alias-feature of the Querydsl Core module with the Scala expression DSL. The result is in our opinion quite compact and readable.

For the moment Querydsl with Scala can be used with JPA, JDO and Mongodb. To get started, you will need the additional querydsl-scala dependency in your project in addition to the dependencies for your Querydsl backend support. Querydsl for Scala has been tested against Scala 2.8.0.

Using Maven you would need to declare the following additional dependency :

<dependency>
      <groupId>com.mysema.querydsl</groupId>
      <artifactId>querydsl-scala</artifactId>
      <version>${querydsl.version}</version>
</dependency>

Here is a minimal example with JPA/Hibernate :

Domain model :

@Entity
class User {
  @BeanProperty
  @Id
  var id: Integer = _;
  @BeanProperty
  var userName: String = _;
  @BeanProperty
  @ManyToOne
  var department: Department = _;
}

@Entity
class Department {
  @BeanProperty
  @Id
  var id: Integer = _;
  @BeanProperty
  var name: String = _;
}

And here are some query examples

import com.mysema.query.scala.Conversions._
import com.mysema.query.jpa.impl.JPAQuery

import com.mysema.query.types.path._
import org.junit.Test

class JPAQueryTest {

  val person = alias(classOf[Person])

  @Test
  def Various() {
    // list
    query from person where (person.firstName $like "Rob%") 
      .list person

    // unique result
    query from person where (person.firstName $like "Rob%") 
      .unique person

    // long where
    query from person 
      .where (person.firstName $like "Rob%", person.lastName $like "An%") 
      .list person

    // order
    query from person orderBy (person.firstName asc) list person

    // not null 
    query from person 
      .where (person.firstName $isEmpty, person.lastName $isNotNull) 
      .list person
  }

  def query() = new JPAQuery(entityManager)

}

The main import for Querydsl Scala integration is the following

import com.mysema.query.scala.Conversions._

The factory method for query creation is

def query() = new JPAQuery(entityManager)

In addition to queries you need variables which can be created like this

var person = alias(classOf[Person])

The person variable is a proxy instance of the the Person class which can be used in queries. Now you can construct your queries, populate them via from-where-...-orderBy calls and get the projection out via list/uniqueResult/listResults calls.

Querydsl expressions are constructed via method calls starting with the "$" sign.

With the Querydsl Java API a simple like expression would be constructed like this :

person.firstName.like("Rob%")

Using the Scala API it is

person.firstName $like "Rob%"

For more examples see src/test/scala in SVN.