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:
parent
60aac117e6
commit
69ee03a79c
|
@ -10,6 +10,7 @@ include::Preface.adoc[]
|
|||
include::chapters/architecture/Architecture.adoc[]
|
||||
include::chapters/domain/DomainModel.adoc[]
|
||||
include::chapters/bootstrap/Bootstrap.adoc[]
|
||||
include::chapters/schema/Schema.adoc[]
|
||||
include::chapters/pc/PersistenceContext.adoc[]
|
||||
include::chapters/flushing/Flushing.adoc[]
|
||||
include::chapters/jdbc/Database_Access.adoc[]
|
||||
|
|
|
@ -556,7 +556,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.
|
||||
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.sql-load-script-source` | |
|
||||
|
|
|
@ -1172,6 +1172,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.
|
||||
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]]
|
||||
.`@Formula` mapping usage
|
||||
====
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -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
|
|
@ -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>
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* 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.LazyGroup;
|
||||
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 )
|
||||
@LazyGroup( "lobs" )
|
||||
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[]
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
create sequence book_sequence start with 1 increment by 1
|
|
@ -27,7 +27,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
* </pre></blockquote>
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* // call functions
|
||||
* // call database functions ( e.g. MySQL upper() and substring() )
|
||||
* @Formula( "upper( substring( middle_name, 1 ) )" )
|
||||
* Character getMiddleInitial() { ... }
|
||||
* </pre></blockquote>
|
||||
|
|
Loading…
Reference in New Issue