HHH-10826 Auxiliary Database Object no longer documented

HHH-10334 @Formula annotation javadoc contains database dependent sample usage

Created a new section related to automatic schema generation
This commit is contained in:
Vlad Mihalcea 2016-06-20 12:34:26 +03:00
parent ea9575294f
commit 0643f909e9
9 changed files with 352 additions and 2 deletions

View File

@ -10,6 +10,7 @@ include::Preface.adoc[]
include::chapters/architecture/Architecture.adoc[] include::chapters/architecture/Architecture.adoc[]
include::chapters/domain/DomainModel.adoc[] include::chapters/domain/DomainModel.adoc[]
include::chapters/bootstrap/Bootstrap.adoc[] include::chapters/bootstrap/Bootstrap.adoc[]
include::chapters/schema/Schema.adoc[]
include::chapters/pc/PersistenceContext.adoc[] include::chapters/pc/PersistenceContext.adoc[]
include::chapters/flushing/Flushing.adoc[] include::chapters/flushing/Flushing.adoc[]
include::chapters/jdbc/Database_Access.adoc[] include::chapters/jdbc/Database_Access.adoc[]

View File

@ -538,7 +538,7 @@ Hibernate historically also accepted `hibernate.hbm2ddl.import_files` for a simi
Comma-separated names of the optional files containing SQL DML statements executed during the `SessionFactory` creation. Comma-separated names of the optional files containing SQL DML statements executed during the `SessionFactory` creation.
File order matters, the statements of a give file are executed before the statements of the following one. File order matters, the statements of a give file are executed before the statements of the following one.
These statements are only executed if the schema is created, meaning that `hibernate.hbm2ddl.auto` is set to `create` or `create-drop`. These statements are only executed if the schema is created, meaning that `hibernate.hbm2ddl.auto` is set to `create`, `create-drop`, or `update`.
`javax.persistence.schema-generation.create-script-source` / `javax.persistence.schema-generation.drop-script-source` should be preferred. `javax.persistence.schema-generation.create-script-source` / `javax.persistence.schema-generation.drop-script-source` should be preferred.
|`javax.persistence.sql-load-script-source` | | |`javax.persistence.sql-load-script-source` | |

View File

@ -1177,6 +1177,11 @@ include::{extrasdir}/basic/mapping-column-read-and-write-composite-type-persiste
Sometimes, you want the Database to do some computation for you rather than in the JVM, you might also create some kind of virtual column. Sometimes, you want the Database to do some computation for you rather than in the JVM, you might also create some kind of virtual column.
You can use a SQL fragment (aka formula) instead of mapping a property into a column. This kind of property is read only (its value is calculated by your formula fragment) You can use a SQL fragment (aka formula) instead of mapping a property into a column. This kind of property is read only (its value is calculated by your formula fragment)
[NOTE]
====
You should be aware that the `@Formula` annotation takes a native SQL clause which can affect database portability.
====
[[mapping-column-formula-example]] [[mapping-column-formula-example]]
.`@Formula` mapping usage .`@Formula` mapping usage
==== ====

View File

@ -0,0 +1,87 @@
[[schema-generation]]
== Schema generation
:sourcedir: ../../../../../test/java/org/hibernate/userguide/schema
:extrasdir: extras
:resourcesdir: ../../../../../test/resources
Hibernate allows you to generate the database from the entity mappings.
[TIP]
====
Although the automatic schema generation is very useful for testing and prototyping purposes, in a production environment,
it's much more flexible to manage the schema using incremental migration scripts.
====
Traditionally, the process of generating schema from entity mapping has been called `HBM2DDL`.
To get a list of Hibernate-native and JPA-specific configuration properties consider reading the <<appendices/Configurations.adoc#configurations-hbmddl,Configurations>> section.
Considering the following Domain Model:
[[schema-generation-domain-model-example]]
.Schema generation Domain Model
====
[source, JAVA, indent=0]
----
include::{sourcedir}/SchemaGenerationTest.java[tags=schema-generation-domain-model-example]
----
====
If the `hibernate.hbm2ddl.auto` configuration is set to `create`, Hibernate is going to generate the following database schema:
[[sql-schema-generation-domain-model-example]]
.Auto-generated database schema
====
[source, SQL, indent=0]
----
include::{extrasdir}/sql-schema-generation-domain-model-example.sql[]
----
====
=== Importing script files
To customize the schema generation process, the `hibernate.hbm2ddl.import_files` configuration property must be used to provide other scripts files that Hibernate can use when the `SessionFactory` is started.
For instance, considering the following `schema-generation.sql` import file:
[[schema-generation-import-file-example]]
.Schema generation import file
====
[source, JAVA, indent=0]
----
include::{resourcesdir}/schema-generation.sql[]
----
====
If we configure Hibernate to import the script above:
[[schema-generation-import-file-configuration-example]]
.Enabling query cache
====
[source, XML, indent=0]
----
<property
name="hibernate.hbm2ddl.import_files"
value="schema-generation.sql" />
----
====
Hibernate is going to execute the script file after the schema is automatically generated.
=== Database objects
Hibernate allows you to customize the schema generation process via the HBM `database-object` element.
Considering the following HBM mapping:
[[schema-generation-database-object-example]]
.Schema generation HBM database-object
====
[source, JAVA, indent=0]
----
include::{sourcedir}/SchemaGenerationTest.hbm.xml[]
----
====
When the `SessionFactory` is bootstrapped, Hibernate is going to execute the `database-object`, therefore creating the `sp_count_books` funtion.

View File

@ -0,0 +1,29 @@
create table Customer (
id integer not null,
accountsPayableXrefId binary,
image blob,
name varchar(255),
primary key (id)
)
create table Book (
id bigint not null,
isbn varchar(255),
title varchar(255),
author_id bigint,
primary key (id)
)
create table Person (
id bigint not null,
name varchar(255),
primary key (id)
)
alter table Book
add constraint UK_u31e1frmjp9mxf8k8tmp990i unique (isbn)
alter table Book
add constraint FKrxrgiajod1le3gii8whx2doie
foreign key (author_id)
references Person

View File

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<database-object>
<create>
CREATE OR REPLACE FUNCTION sp_count_books(
IN authorId bigint,
OUT bookCount bigint)
RETURNS bigint AS
$BODY$
BEGIN
SELECT COUNT(*) INTO bookCount
FROM book
WHERE author_id = authorId;
END;
$BODY$
LANGUAGE plpgsql;
</create>
<drop></drop>
<dialect-scope name="org.hibernate.dialect.PostgreSQL95Dialect" />
</database-object>
</hibernate-mapping>

View File

@ -0,0 +1,202 @@
/*
* 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.schema;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import org.hibernate.annotations.NaturalId;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.RequiresDialect;
import org.junit.Test;
/**
* @author Vlad Mihalcea
*/
public class SchemaGenerationTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class,
Book.class,
Customer.class
};
}
@Override
protected void addConfigOptions(Map options) {
if ( getDialect().getClass().equals( H2Dialect.class ) ) {
options.put(
AvailableSettings.HBM2DDL_IMPORT_FILES,
"schema-generation.sql"
);
options.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "update" );
}
}
@Override
protected String[] getMappings() {
if ( PostgreSQL81Dialect.class.isAssignableFrom( getDialect().getClass() ) ) {
return new String[] { "org/hibernate/userguide/schema/SchemaGenerationTest.hbm.xml" };
}
return super.getMappings();
}
@Test
@RequiresDialect( H2Dialect.class )
public void testH2() {
}
@Test
@RequiresDialect( PostgreSQL81Dialect.class )
public void testPostgres() {
}
//tag::schema-generation-domain-model-example[]
@Entity(name = "Customer")
public class Customer {
@Id
private Integer id;
private String name;
@Basic( fetch = FetchType.LAZY )
private UUID accountsPayableXrefId;
@Lob
@Basic( fetch = FetchType.LAZY )
private Blob image;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public UUID getAccountsPayableXrefId() {
return accountsPayableXrefId;
}
public void setAccountsPayableXrefId(UUID accountsPayableXrefId) {
this.accountsPayableXrefId = accountsPayableXrefId;
}
public Blob getImage() {
return image;
}
public void setImage(Blob image) {
this.image = image;
}
}
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
private String name;
@OneToMany(mappedBy = "author")
private List<Book> books = new ArrayList<>( );
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 List<Book> getBooks() {
return books;
}
}
@Entity(name = "Book")
public static class Book {
@Id
private Long id;
private String title;
@NaturalId
private String isbn;
@ManyToOne
private Person author;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Person getAuthor() {
return author;
}
public void setAuthor(Person author) {
this.author = author;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
}
//end::schema-generation-domain-model-example[]
}

View File

@ -0,0 +1 @@
create sequence book_sequence start with 1 increment by 1

View File

@ -27,7 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
* </pre></blockquote> * </pre></blockquote>
* *
* <blockquote><pre> * <blockquote><pre>
* // call functions * // call database functions ( e.g. MySQL upper() and substring() )
* &#064;Formula( "upper( substring( middle_name, 1 ) )" ) * &#064;Formula( "upper( substring( middle_name, 1 ) )" )
* Character getMiddleInitial() { ... } * Character getMiddleInitial() { ... }
* </pre></blockquote> * </pre></blockquote>