Skip to content

Commit

Permalink
HHH-10523 - 2.3.20. SQL quoted identifiers in User Guide should discu…
Browse files Browse the repository at this point in the history
…ss explicit enclosure in double-quotes (JPA)
  • Loading branch information
vladmihalcea committed Aug 10, 2016
1 parent cdb11f9 commit 80770ab
Show file tree
Hide file tree
Showing 4 changed files with 242 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1012,18 +1012,29 @@ include::{extrasdir}/basic/basic-jpa-convert-period-string-converter-sql-example
==== SQL quoted identifiers

You can force Hibernate to quote an identifier in the generated SQL by enclosing the table or column name in backticks in the mapping document.
Hibernate will use the correct quotation style for the SQL `Dialect`.
This is usually double quotes, but the SQL Server uses brackets and MySQL uses backticks.
While traditionally, Hibernate used backticks for escaping SQL reserved keywords, JPA uses double quotes instead.

Once the reserved keywords are escaped, Hibernate will use the correct quotation style for the SQL `Dialect`.
This is usually double quotes, but SQL Server uses brackets and MySQL uses backticks.

[[basic-quoting-example]]
.Quoting column names
.Hibernate legacy quoting
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/QuotingTest.java[tags=basic-quoting-example]
----
====

[[basic-jpa-quoting-example]]
.JPA quoting
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JpaQuotingTest.java[tags=basic-jpa-quoting-example]
----
====

Because `name` and `number` are reserved words, the `Product` entity mapping uses backtricks to quote these column names.

When saving teh following `Product entity`, Hibernate generates the following SQL insert statement:
Expand All @@ -1034,11 +1045,53 @@ When saving teh following `Product entity`, Hibernate generates the following SQ
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/QuotingTest.java[tags=basic-quoting-persistence-example, indent=0]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/basic-quoting-persistence-example.sql[indent=0]
----
====

[[mapping-global-quoted-identifiers]]
===== Global quoting

Hibernate can also quote all identifiers (e.g. table, columns) using the following configuration property:

====
[source,xml]
----
<property
name="hibernate.globally_quoted_identifiers"
value="true"
/>
----
====

This way, we don't need to manually quote any identifier:

[[basic-auto-quoting-example]]
.JPA quoting
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/AutoQuotingTest.java[tags=basic-auto-quoting-example]
----
====

When persisting a `Product` entity, Hibernate is going to quote all identifiers as in the following example:

====
[source, SQL, indent=0]
----
include::{extrasdir}/basic/basic-auto-quoting-persistence-example.sql[indent=0]
----
====

As you can see, both the table name and all the column have been quoted.

For more about quoting-related configuration properties, checkout the <<appendices/Configurations.adoc#configurations-mapping,Mapping configurations>> section as well.

[[mapping-generated]]
==== Generated properties

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
INSERT INTO "Product" ("name", "number", "id")
VALUES ('Mobile phone', '123-456-7890', 1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.userguide.mapping.basic;

import java.util.Map;
import javax.persistence.Entity;
import javax.persistence.Id;

import org.hibernate.cfg.AvailableSettings;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;

import org.junit.Test;

import static org.hibernate.userguide.util.TransactionUtil.doInJPA;

/**
* @author Vlad Mihalcea
*/
public class AutoQuotingTest extends BaseEntityManagerFunctionalTestCase {

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Product.class
};
}

@Override
protected Map buildSettings() {
Map settings = super.buildSettings();
settings.put( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, true );
return settings;
}

@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::basic-auto-quoting-persistence-example[]
Product product = new Product();
product.setId( 1L );
product.setName( "Mobile phone" );
product.setNumber( "123-456-7890" );
entityManager.persist( product );
//end::basic-auto-quoting-persistence-example[]
} );
}

//tag::basic-auto-quoting-example[]
@Entity(name = "Product")
public static class Product {

@Id
private Long id;

private String name;

private String number;

//Getters and setters are omitted for brevity

//end::basic-auto-quoting-example[]

public Long getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getNumber() {
return number;
}

public void setNumber(String number) {
this.number = number;
}


//tag::basic-auto-quoting-example[]
}
//end::basic-auto-quoting-example[]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.userguide.mapping.basic;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;

import org.junit.Test;

import static org.hibernate.userguide.util.TransactionUtil.doInJPA;

/**
* @author Vlad Mihalcea
*/
public class JpaQuotingTest extends BaseEntityManagerFunctionalTestCase {

@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Product.class
};
}

@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::basic-jpa-quoting-persistence-example[]
Product product = new Product();
product.setId( 1L );
product.setName( "Mobile phone" );
product.setNumber( "123-456-7890" );
entityManager.persist( product );
//end::basic-jpa-quoting-persistence-example[]
} );
}

//tag::basic-jpa-quoting-example[]
@Entity(name = "Product")
public static class Product {

@Id
private Long id;

@Column(name = "\"name\"")
private String name;

@Column(name = "\"number\"")
private String number;

//Getters and setters are omitted for brevity

//end::basic-jpa-quoting-example[]

public Long getId() {
return id;
}

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

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getNumber() {
return number;
}

public void setNumber(String number) {
this.number = number;
}


//tag::basic-jpa-quoting-example[]
}
//end::basic-jpa-quoting-example[]
}

0 comments on commit 80770ab

Please sign in to comment.