querydsl/querydsl-docs/src/main/docbook/en-US/content/tutorials/sql.xml
2015-11-10 08:28:31 -07:00

1159 lines
36 KiB
XML

<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<sect1 id="sql_integration" revision="1">
<title>Querying SQL</title>
<para>This chapter describes the query type generation and querying functionality of the
SQL module.</para>
<sect2>
<title>Maven integration</title>
<para>
Add the following dependencies to your Maven project:
</para>
<programlisting language="xml"><![CDATA[
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-sql</artifactId>
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>com.mysema.querydsl</groupId>
<artifactId>querydsl-sql-codegen</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
]]></programlisting>
<para>The querydsl-sql-codegen dependency can be skipped, if code generation happens
via Maven or Ant.</para>
</sect2>
<sect2>
<title>Code generation via Maven</title>
<para>This functionality should be primarily used via the Maven plugin. Here is an example:
</para>
<programlisting language="xml"><![CDATA[
<project>
<build>
<plugins>
...
<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>
...
</plugins>
</build>
</project>
]]></programlisting>
<para>
Use the goal <emphasis>test-export</emphasis>
to add the targetFolder as a test compile source root
instead of a compile source root.
</para>
<table>
<title>Parameters</title>
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
<colspec colname='Name' colwidth="1*" />
<colspec colname='Descriptions' colwidth="1*" />
<thead>
<row>
<entry>Name</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>jdbcDriver</entry>
<entry>class name of the JDBC driver</entry>
</row>
<row>
<entry>jdbcUrl</entry>
<entry>JDBC url</entry>
</row>
<row>
<entry>jdbcUser</entry>
<entry>JDBC user</entry>
</row>
<row>
<entry>jdbcPassword</entry>
<entry>JDBC password</entry>
</row>
<row>
<entry>namePrefix</entry>
<entry>name prefix for generated query classes (default: Q)</entry>
</row>
<row>
<entry>nameSuffix</entry>
<entry>name suffix for generated query classes (default: )</entry>
</row>
<row>
<entry>beanPrefix</entry>
<entry>name prefix for generated bean classes</entry>
</row>
<row>
<entry>beanSuffix</entry>
<entry>name suffix for generated bean classes</entry>
</row>
<row>
<entry>packageName</entry>
<entry>package name where source files should be generated</entry>
</row>
<row>
<entry>beanPackageName</entry>
<entry>package name where bean files should be generated, (default:
packageName)</entry>
</row>
<row>
<entry>beanInterfaces</entry>
<entry>array of interface classnames to add to the bean classes (default: empty)</entry>
</row>
<row>
<entry>beanAddToString</entry>
<entry>set to true to create a default toString() implementation (default: false)</entry>
</row>
<row>
<entry>beanAddFullConstructor</entry>
<entry>set to true to create a full constructor in addition to public empty (default: false)</entry>
</row>
<row>
<entry>beanPrintSupertype</entry>
<entry>set to true to print the supertype as well (default: false)</entry>
</row>
<row>
<entry>schemaPattern</entry>
<entry>a schema name pattern in LIKE pattern form; must match the schema name as it is stored in the database;
(default: null)</entry>
</row>
<row>
<entry>tableNamePattern</entry>
<entry>a table name pattern in LIKE pattern form; must match the table name as it is stored in the database,
multiple can be separated by comma
(default: null)</entry>
</row>
<row>
<entry>targetFolder</entry>
<entry>target folder where source folder should be generated</entry>
</row>
<row>
<entry>namingStrategyClass</entry>
<entry>class name of the NamingStrategy class (default: DefaultNamingStrategy)
</entry>
</row>
<row>
<entry>beanSerializerClass</entry>
<entry>class name of the BeanSerializer class (default: BeanSerializer)</entry>
</row>
<row>
<entry>serializerClass</entry>
<entry>class name of the Serializer class (default: MetaDataSerializer)</entry>
</row>
<row>
<entry>exportBeans</entry>
<entry>set to true to generate beans as well, see section 2.14.13 (default:
false)</entry>
</row>
<row>
<entry>innerClassesForKeys</entry>
<entry>set to true to generate inner classes for keys (default: false)</entry>
</row>
<row>
<entry>validationAnnotations</entry>
<entry>set to true to enable serialization of validation annotations
(default: false)</entry>
</row>
<row>
<entry>columnAnnotations</entry>
<entry>export column annotations (default: false)</entry>
</row>
<row>
<entry>createScalaSources</entry>
<entry>whether to export Scala sources instead of Java sources, (default:
false)</entry>
</row>
<row>
<entry>schemaToPackage</entry>
<entry>append schema name to package (default: false)</entry>
</row>
<row>
<entry>lowerCase</entry>
<entry>lower case transformation of names (default: false)</entry>
</row>
<row>
<entry>exportTables</entry>
<entry>export tables (default: true)</entry>
</row>
<row>
<entry>exportViews</entry>
<entry>export views (default: true)</entry>
</row>
<row>
<entry>exportPrimaryKeys</entry>
<entry>export primary keys (default: true)</entry>
</row>
<row>
<entry>tableTypesToExport</entry>
<entry>Comma-separated list of table types to export (allowable values will depend on JDBC driver). Allows for arbitrary set of types to be exported, e.g.: "TABLE, MATERIALIZED VIEW". The exportTables and exportViews parameters will be ignored if this parameter is set. (default: none)</entry>
</row>
<row>
<entry>exportForeignKeys</entry>
<entry>export foreign keys (default: true)</entry>
</row>
<row>
<entry>customTypes</entry>
<entry>Custom user types (default: none)</entry>
</row>
<row>
<entry>typeMappings</entry>
<entry>Mappings of table.column to Java type (default: none)</entry>
</row>
<row>
<entry>numericMappings</entry>
<entry>Mappings of size/digits to Java type (default: none)</entry>
</row>
<row>
<entry>imports</entry>
<entry>Array of java imports added to generated query classes: <emphasis>com.bar</emphasis> for package (without .* notation), <emphasis>com.bar.Foo</emphasis> for class (default: empty)
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>Custom types can be used to register additional Type implementations:</para>
<programlisting language="xml"><![CDATA[
<customTypes>
<customType>com.mysema.query.sql.types.InputStreamType</customType>
</customTypes>
]]></programlisting>
<para>Type mappings can be used to register table.column specific java types:</para>
<programlisting language="xml"><![CDATA[
<typeMappings>
<typeMapping>
<table>IMAGE</table>
<column>CONTENTS</column>
<type>java.io.InputStream</type>
</typeMapping>
</typeMappings>
]]></programlisting>
<para>The defaults for the numeric mappings are </para>
<table>
<title>Numeric mappings</title>
<tgroup cols='3' align='left' colsep='1' rowsep='1'>
<colspec colname='Name' colwidth="1*" />
<colspec colname='Descriptions' colwidth="1*" />
<thead>
<row>
<entry>Total digits</entry>
<entry>Decimal digits</entry>
<entry>Type</entry>
</row>
</thead>
<tbody>
<row>
<entry>&gt; 18</entry>
<entry>0</entry>
<entry>BigInteger</entry>
</row>
<row>
<entry>&gt; 9</entry>
<entry>0</entry>
<entry>Long</entry>
</row>
<row>
<entry>&gt; 4</entry>
<entry>0</entry>
<entry>Integer</entry>
</row>
<row>
<entry>&gt; 2</entry>
<entry>0</entry>
<entry>Short</entry>
</row>
<row>
<entry>&gt; 0</entry>
<entry>0</entry>
<entry>Byte</entry>
</row>
<row>
<entry>&gt; 16</entry>
<entry>&gt; 0</entry>
<entry>BigDecimal</entry>
</row>
<row>
<entry>&gt; 0</entry>
<entry>&gt; 0</entry>
<entry>Double</entry>
</row>
</tbody>
</tgroup>
</table>
<para>They can be customized for specific total/decimal digits combinations like this:</para>
<programlisting language="xml"><![CDATA[
<numericMappings>
<numericMapping>
<total>1</total>
<decimal>0</decimal>
<javaType>java.lang.Byte</javaType>
</numericMapping>
</numericMappings>
]]></programlisting>
<para>Imports can be used to add cross-schema foreign keys support.</para>
<para>Compared to APT based code generation certain functionality is not available such as QueryDelegate annotation handling.</para>
</sect2>
<sect2>
<title>Code generation via ANT</title>
<para>
The ANT task <code>com.mysema.query.sql.ant.AntMetaDataExporter</code>
of the querydsl-sql module provides the same functionality as an ANT task.
The configuration parameters of the task are the same as for the Maven plugin.
</para>
</sect2>
<sect2>
<title>Creating the query types</title>
<para>To get started export your schema into Querydsl query types like this:</para>
<programlisting language="java"><![CDATA[
java.sql.Connection conn = ...;
MetaDataExporter exporter = new MetaDataExporter();
exporter.setPackageName("com.myproject.mydomain");
exporter.setTargetFolder(new File("target/generated-sources/java"));
exporter.export(conn.getMetaData());
]]></programlisting>
<para>This declares that the database schema is to be mirrored into the
com.myproject.domain package in the target/generated-sources/java folder.
</para>
<para>
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.
</para>
<para>
In addition to this primary key and foreign key constraints are provided as fields
which can be used for compact join declarations.
</para>
</sect2>
<sect2>
<title>Configuration</title>
<para>The configuration is done via the com.mysema.query.sql.Configuration class which takes the
Querydsl SQL dialect as an argument. For H2 you would create it like this</para>
<programlisting language="java"><![CDATA[
SQLTemplates templates = new H2Templates();
Configuration configuration = new Configuration(templates);
]]></programlisting>
<para>Querydsl uses SQL dialects to customize the SQL serialization needed for
different relational databases. The available dialects are:
</para>
<itemizedlist>
<listitem>
<para>CUBRIDTemplates (tested with CUBRID 8.4)</para>
</listitem>
<listitem>
<para>DB2Templates (tested with DB2 10.1.2)</para>
</listitem>
<listitem>
<para>DerbyTemplates (tested with Derby 10.8.2.2)</para>
</listitem>
<listitem>
<para>FirebirdTemplates (tested with Firebird 2.5)</para>
</listitem>
<listitem>
<para>HSQLDBTemplates (tested with HSQLDB 2.2.4)</para>
</listitem>
<listitem>
<para>H2Templates (tested with H2 1.3.164)</para>
</listitem>
<listitem>
<para>MySQLTemplates (tested with MySQL 5.5)</para>
</listitem>
<listitem>
<para>OracleTemplates (test with Oracle 10 and 11)</para>
</listitem>
<listitem>
<para>PostgresTemplates (tested with PostgreSQL 9.1)</para>
</listitem>
<listitem>
<para>SQLiteTemplates (tested with xerial JDBC 3.7.2)</para>
</listitem>
<listitem>
<para>SQLServerTemplates (tested with SQL Server)</para>
</listitem>
<listitem>
<para>SQLServer2005Templates (for SQL Server 2005)</para>
</listitem>
<listitem>
<para>SQLServer2008Templates (for SQL Server 2008)</para>
</listitem>
<listitem>
<para>SQLServer2012Templates (for SQL Server 2012 and later)</para>
</listitem>
<listitem>
<para>TeradataTemplates (tested with Teradata 14)</para>
</listitem>
</itemizedlist>
<para>For customized SQLTemplates instances you can use the builder pattern like this</para>
<programlisting language="java"><![CDATA[
H2Templates.builder()
.printSchema() // to include the schema in the output
.quote() // to quote names
.newLineToSingleSpace() // to replace new lines with single space in the output
.escape(ch) // to set the escape char
.build(); // to get the customized SQLTemplates instance
]]></programlisting>
<para>The methods of the Configuration class can be used to enable direct serialization of literals
via setUseLiterals(true), override schema and tables and register custom types. For full details look
at the javadocs of Configuration.</para>
</sect2>
<sect2>
<title>Querying</title>
<para>Querying with Querydsl SQL is as simple as this:</para>
<programlisting language="java"><![CDATA[
QCustomer customer = new QCustomer("c");
SQLQuery query = new SQLQuery(connection, configuration);
List<String> lastNames = query.from(customer)
.where(customer.firstName.eq("Bob"))
.list(customer.lastName);
]]></programlisting>
<para>
which is transformed into the following sql query, assuming that the related table
name is <emphasis>customer</emphasis>
and the columns <emphasis>first_name</emphasis>
and <emphasis>last_name</emphasis>:
</para>
<programlisting><![CDATA[
SELECT c.last_name
FROM customer c
WHERE c.first_name = 'Bob'
]]></programlisting>
</sect2>
<sect2>
<title>General usage</title>
<para>Use the the cascading methods of the SQLQuery class like this</para>
<para>
<emphasis>from:</emphasis>
Add the query sources here.
</para>
<para>
<emphasis>innerJoin, join, leftJoin, fullJoin, on:</emphasis>
Add join elements using these constructs.
For the join methods the first argument is the join source and the second the target
(alias).
</para>
<para>
<emphasis>where:</emphasis>
Add query filters, either in varargs form separated via commas or
cascaded via the and-operator.
</para>
<para>
<emphasis>groupBy:</emphasis>
Add group by arguments in varargs form.
</para>
<para>
<emphasis>having:</emphasis>
Add having filter of the "group by" grouping as an varags array of
Predicate expressions.
</para>
<para>
<emphasis>orderBy:</emphasis>
Add 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.
</para>
<para>
<emphasis>limit, offset, restrict:</emphasis>
Set the paging of the result. Limit for max results,
offset for skipping rows and restrict for defining both in one call.
</para>
</sect2>
<sect2>
<title>Joins</title>
<para>Joins are constructed using the following syntax:</para>
<programlisting language="java"><![CDATA[
QCustomer customer = QCustomer.customer;
QCompany company = QCompany.company;
query.from(customer)
.innerJoin(customer.company, company)
.list(customer.firstName, customer.lastName, company.name);
]]></programlisting>
<para>and for a left join:</para>
<programlisting language="java"><![CDATA[
query.from(customer)
.leftJoin(customer.company, company)
.list(customer.firstName, customer.lastName, company.name);
]]></programlisting>
<para>Alternatively the join condition can also be written out:</para>
<programlisting language="java"><![CDATA[
query.from(customer)
.leftJoin(company).on(customer.company.eq(company.id))
.list(customer.firstName, customer.lastName, company.name);
]]></programlisting>
</sect2>
<sect2>
<title>Ordering</title>
<para>The syntax for declaring ordering is </para>
<programlisting language="java"><![CDATA[
query.from(customer)
.orderBy(customer.lastName.asc(), customer.firstName.asc())
.list(customer.firstName, customer.lastName);
]]></programlisting>
<para>which is equivalent to the following native SQL</para>
<programlisting>
SELECT c.first_name, c.last_name
FROM customer c
ORDER BY c.last_name ASC, c.first_name ASC
</programlisting>
</sect2>
<sect2>
<title>Grouping</title>
<para>Grouping can be done in the following form</para>
<programlisting language="java"><![CDATA[
query.from(customer)
.groupBy(customer.lastName)
.list(customer.lastName);
]]></programlisting>
<para>which is equivalent to the following native SQL</para>
<programlisting>
SELECT c.last_name
FROM customer c
GROUP BY c.last_name
</programlisting>
</sect2>
<!-- <sect2> <title>Union queries</title> <para>TODO</para> </sect2> -->
<sect2>
<title>Using Subqueries</title>
<para>
To create a subquery you create a 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.
</para>
<programlisting language="java"><![CDATA[
QCustomer customer = QCustomer.customer;
QCustomer customer2 = new QCustomer("customer2");
query.from(customer).where(
customer.status.eq(new SQLSubQuery().from(customer2).unique(customer2.status.max()))
.list(customer.all())
]]></programlisting>
<para>Another example</para>
<programlisting language="java"><![CDATA[
QStatus status = QStatus.status;
query.from(customer).where(
customer.status.in(new SQLSubQuery().from(status).where(status.level.lt(3)).list(status.id))
.list(customer.all())
]]></programlisting>
</sect2>
<sect2>
<title>Selecting literals</title>
<para>To select literals you need to create constant instances for them like this:</para>
<programlisting language="java"><![CDATA[
query.list(Expressions.constant(1),
Expressions.constant("abc"));
]]></programlisting>
<para>The class <code>com.mysema.query.support.Expressions</code> offers also other useful static methods for
projections, operation and template creation.</para>
</sect2>
<sect2>
<title>Query extension support</title>
<para>Custom query extensions to support engine specific syntax can be created by
subclassing AbstractSQLQuery and adding flagging methods like
in the given MySQLQuery example:
</para>
<programlisting language="java"><![CDATA[
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 ");
}
// ...
}
]]></programlisting>
<para>
The flags are custom SQL snippets that can be inserted at specific points in the
serialization. The supported positions are the enums of the
<code>com.mysema.query.QueryFlag.Position</code> enum class.
</para>
</sect2>
<sect2>
<title>Window functions</title>
<para>Window functions are supported in Querydsl via the methods in the <code>SQLExpressions</code> class.</para>
<para>Usage example:</para>
<programlisting language="java"><![CDATA[
query.from(employee)
.list(SQLExpressions.rowNumber()
.over()
.partitionBy(employee.name)
.orderBy(employee.id));
]]></programlisting>
</sect2>
<sect2>
<title>Common table expressions</title>
<para>Common table expressions are supported in Querydsl SQL via two syntax variants</para>
<programlisting language="java"><![CDATA[
QEmployee employee = QEmployee.employee;
query.with(employee, sq().from(employee).where(employee.name.startsWith("A")).list(employee.all()))
.from(...)
]]></programlisting>
<para>And using a column listing</para>
<programlisting language="java"><![CDATA[
QEmployee employee = QEmployee.employee;
query.with(employee, employee.id, employee.name)
.as(sq().from(employee).where(employee.name.startsWith("A")).list(employee.id, employee.name))
.from(...)
]]></programlisting>
<para>If the columns of the common table expression are a subset of an existing table or view
it is advisable to use a generated path type for it, e.g. QEmployee in this case, but if the
columns don't fit any existing table PathBuilder can be used instead.</para>
<para>Below is an example for such a case</para>
<programlisting language="java"><![CDATA[
QEmployee employee = QEmployee.employee;
QDepartment department = QDepartment.department;
PathBuilder<Tuple> emp = new PathBuilder<Tuple>(Tuple.class, "emp");
query.with(emp, sq().from(employee).innerJoin(department).on(employee.departmentId.eq(department.id))
.list(employee.id, employee.name, employee.departmentId,
department.name.as("departmentName")))
.from(...)
]]></programlisting>
</sect2>
<sect2>
<title>Other SQL expressions</title>
<para>
Other SQL expressions are also available from the <code>SQLExpressions</code> class as static methods.
</para>
</sect2>
<sect2>
<title>Using Data manipulation commands</title>
<para>All the DMLClause implementation in the Querydsl SQL module take three
parameters, the Connection, the SQLTemplates instance
used in the queries and the main entity the DMLClause is bound to.
</para>
<sect3>
<title>Insert</title>
<para>With columns</para>
<programlisting language="java"><![CDATA[
QSurvey survey = QSurvey.survey;
new SQLInsertClause(conn, configuration, survey)
.columns(survey.id, survey.name)
.values(3, "Hello").execute();
]]></programlisting>
<para>Without columns</para>
<programlisting language="java"><![CDATA[
new SQLInsertClause(conn, configuration, survey)
.values(4, "Hello").execute();
]]></programlisting>
<para>With subquery</para>
<programlisting language="java"><![CDATA[
new SQLInsertClause(conn, configuration, survey)
.columns(survey.id, survey.name)
.select(new SQLSubQuery().from(survey2).list(survey2.id.add(1), survey2.name))
.execute();
]]></programlisting>
<para>With subquery, without columns</para>
<programlisting language="java"><![CDATA[
new SQLInsertClause(conn, configuration, survey)
.select(new SQLSubQuery().from(survey2).list(survey2.id.add(10), survey2.name))
.execute();
]]></programlisting>
<para>As an alternative to the columns/values usage, Querydsl provides also a set
method which can be used like this</para>
<programlisting language="java"><![CDATA[
QSurvey survey = QSurvey.survey;
new SQLInsertClause(conn, configuration, survey)
.set(survey.id, 3)
.set(survey.name, "Hello").execute();
]]></programlisting>
<para>which is equivalent to the first example. Usage of the set method always
expands internally to columns and values.</para>
<para>Beware that</para>
<programlisting language="java"><![CDATA[
columns(...).select(...)
]]></programlisting>
<para>maps the result set of the given query to be inserted whereas</para>
<para>To get the created keys out instead of modified rows count use one of the executeWithKey/s method.</para>
<programlisting language="java"><![CDATA[
set(...)
]]></programlisting>
<para>maps single columns and nulls are used for empty subquery results.</para>
<para>To populate a clause instance based on the contents of a bean you can use</para>
<programlisting language="java"><![CDATA[
new SQLInsertClause(conn, configuration, survey)
.populate(surveyBean).execute();
]]></programlisting>
<para>This will exclude null bindings, if you need also null bindings use</para>
<programlisting language="java"><![CDATA[
new SQLInsertClause(conn, configuration, survey)
.populate(surveyBean, DefaultMapper.WITH_NULL_BINDINGS).execute();
]]></programlisting>
</sect3>
<sect3>
<title>Update</title>
<para>With where</para>
<programlisting language="java"><![CDATA[
QSurvey survey = QSurvey.survey;
new SQLUpdateClause(conn, configuration, survey)
.where(survey.name.eq("XXX"))
.set(survey.name, "S")
.execute();
]]></programlisting>
<para>Without where</para>
<programlisting language="java"><![CDATA[
new SQLUpdateClause(conn, configuration, survey)
.set(survey.name, "S")
.execute();
]]></programlisting>
<para>Using bean population</para>
<programlisting language="java"><![CDATA[
new SQLUpdateClause(conn, configuration, survey)
.populate(surveyBean)
.execute();
]]></programlisting>
</sect3>
<sect3>
<title>Delete</title>
<para>With where</para>
<programlisting language="java"><![CDATA[
QSurvey survey = QSurvey.survey;
new SQLDeleteClause(conn, configuration, survey)
.where(survey.name.eq("XXX"))
.execute();
]]></programlisting>
<para>Without where</para>
<programlisting language="java"><![CDATA[
new SQLDeleteClause(conn, configuration, survey)
.execute()
]]></programlisting>
</sect3>
</sect2>
<sect2>
<title>Batch support in DML clauses</title>
<para>Querydsl SQL supports usage of JDBC batch updates through the DML APIs. If you
have consecutive DML calls with a similar structure,
you can bundle the the calls via addBatch() usage into one DMLClause. See the examples how
it works for UPDATE, DELETE and INSERT.
</para>
<para>Update:</para>
<programlisting language="java"><![CDATA[
QSurvey survey = QSurvey.survey;
insert(survey).values(2, "A").execute();
insert(survey).values(3, "B").execute();
SQLUpdateClause update = update(survey);
update.set(survey.name, "AA").where(survey.name.eq("A")).addBatch();
update.set(survey.name, "BB").where(survey.name.eq("B")).addBatch();
]]></programlisting>
<para>Delete:</para>
<programlisting language="java"><![CDATA[
insert(survey).values(2, "A").execute();
insert(survey).values(3, "B").execute();
SQLDeleteClause delete = delete(survey);
delete.where(survey.name.eq("A")).addBatch();
delete.where(survey.name.eq("B")).addBatch();
assertEquals(2, delete.execute());
]]></programlisting>
<para>Insert:</para>
<programlisting language="java"><![CDATA[
SQLInsertClause insert = insert(survey);
insert.set(survey.id, 5).set(survey.name, "5").addBatch();
insert.set(survey.id, 6).set(survey.name, "6").addBatch();
assertEquals(2, insert.execute());
]]></programlisting>
</sect2>
<sect2>
<title>Bean class generation</title>
<para>To create JavaBean DTO types for the tables of your schema use the
MetaDataExporter like this:</para>
<programlisting language="java"><![CDATA[
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());
]]></programlisting>
<para>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 in JUnit form:
</para>
<programlisting language="java"><![CDATA[
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());
]]></programlisting>
<para>The factory methods used in the previous example are here:</para>
<programlisting language="java"><![CDATA[
protected SQLUpdateClause update(RelationalPath<?> e) {
return new SQLUpdateClause(Connections.getConnection(), templates, e);
}
protected SQLInsertClause insert(RelationalPath<?> e) {
return new SQLInsertClause(Connections.getConnection(), templates, e);
}
protected SQLDeleteClause delete(RelationalPath<?> e) {
return new SQLDeleteClause(Connections.getConnection(), templates, e);
}
protected SQLMergeClause merge(RelationalPath<?> e) {
return new SQLMergeClause(Connections.getConnection(), templates, e);
}
protected SQLQuery query() {
return new SQLQuery(Connections.getConnection(), templates);
}
]]></programlisting>
</sect2>
<!--
<sect2>
<title>Custom syntax expressions</title>
<para>
If you need to specify SQL function calls in Querydsl you can use TemplateExpressions to
express them. For general expressions you can use the SimpleTemplate class and for typed
expressions BooleanTemplate, ComparableTemplate, DateTemplate,
DateTimeTemplate, EnumTemplate, NumberTemplate, StringTemplate and TimeTemplate.
</para>
<para>Here is an example for SimpleTemplate usage:</para>
<programlisting language="java"><![CDATA[
Expression<?> arg1 = ...;
Expression<?> arg2 = ...;
Expression<String> expression = SimpleTemplate.create(String.class, "myfunction({0},{1})", arg1, arg2);
]]></programlisting>
<para>And here is an example for a Number typed template expression:</para>
<programlisting language="java"><![CDATA[
Expression<?> arg1 = ...;
Expression<?> arg2 = ...;
NumberExpression<Integer> expression = NumberTemplate.create(Integer.class, "myfunction({0},{1})", arg1, arg2);
]]></programlisting>
</sect2>
-->
<sect2>
<title>Extracting the SQL query and bindings</title>
<para>The SQL query and bindings can be extracted via the getSQL method:</para>
<programlisting language="java"><![CDATA[
SQLBindings bindings = query.getSQL(customer.id, customer.firstname, customer.lastname);
System.out.println(bindings.getSQL());
]]></programlisting>
<para>If you need also all literals in the SQL string you can enable literal serialization on the
query or configuration level via setUseLiterals(true).</para>
</sect2>
<sect2>
<title>Custom types</title>
<para>Querydsl SQL provides the possibility to declare custom type mappings for
ResultSet/Statement interaction. The custom type mappings can be
declared in com.mysema.query.sql.Configuration instances, which are supplied as constructor
arguments to the actual queries:
</para>
<programlisting language="java"><![CDATA[
Configuration configuration = new Configuration(new H2Templates());
// overrides the mapping for Types.DATE
configuration.register(new UtilDateType());
]]></programlisting>
<para>And for a table column</para>
<programlisting language="java"><![CDATA[
Configuration configuration = new Configuration(new H2Templates());
// declares a mapping for the gender column in the person table
configuration.register("person", "gender", new EnumByNameType<Gender>(Gender.class));
]]></programlisting>
<para>To customize a numeric mapping you can use the registerNumeric method like this
</para>
<programlisting language="java"><![CDATA[
configuration.registerNumeric(5,2,Float.class);
]]></programlisting>
<para>This will map the Float type to the NUMERIC(5,2) type.</para>
</sect2>
<sect2>
<title>Listening to queries and clauses</title>
<para>SQLListener is a listener interface that can be used to listen to queries and DML clause. SQLListener
instances can be registered either on the configuration and on the query/clause level via the addListener method.</para>
<para>Use cases for listeners are data synchronization, logging, caching and validation.</para>
</sect2>
</sect1>