HHH-10523 - 2.3.20. SQL quoted identifiers in User Guide should discuss explicit enclosure in double-quotes (JPA)

This commit is contained in:
Vlad Mihalcea 2016-08-10 11:02:59 +03:00
parent cdb11f9be2
commit 80770ab13b
4 changed files with 242 additions and 3 deletions

View File

@ -1012,11 +1012,13 @@ include::{extrasdir}/basic/basic-jpa-convert-period-string-converter-sql-example
==== SQL quoted identifiers ==== 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. 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`. While traditionally, Hibernate used backticks for escaping SQL reserved keywords, JPA uses double quotes instead.
This is usually double quotes, but the SQL Server uses brackets and MySQL uses backticks.
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]] [[basic-quoting-example]]
.Quoting column names .Hibernate legacy quoting
==== ====
[source, JAVA, indent=0] [source, JAVA, indent=0]
---- ----
@ -1024,6 +1026,15 @@ 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. 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: When saving teh following `Product entity`, Hibernate generates the following SQL insert statement:
@ -1034,11 +1045,53 @@ When saving teh following `Product entity`, Hibernate generates the following SQ
[source, JAVA, indent=0] [source, JAVA, indent=0]
---- ----
include::{sourcedir}/basic/QuotingTest.java[tags=basic-quoting-persistence-example, 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] 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]] [[mapping-generated]]
==== Generated properties ==== Generated properties

View File

@ -0,0 +1,2 @@
INSERT INTO "Product" ("name", "number", "id")
VALUES ('Mobile phone', '123-456-7890', 1)

View File

@ -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[]
}

View File

@ -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[]
}