HHH-11186 - Add examples for all Hibernate annotations
Document @UniqueConstraint annotation
This commit is contained in:
parent
87ddf0e74b
commit
c0b0da4282
|
@ -16,6 +16,8 @@ See the <<chapters/domain/access.adoc#access,Access type>> section for more info
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/AssociationOverride.html[`@AssociationOverride`] annotation is used to override an association mapping (e.g. `@ManyToOne`, `@OneToOne`, `@OneToMany`, `@ManyToMany`) inherited from a mapped superclass or an embeddable.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-associationoverrides]]
|
||||
==== `@AssociationOverrides`
|
||||
|
||||
|
@ -26,6 +28,8 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/AssociationOverrides.h
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/AttributeOverride.html[`@AttributeOverride`] annotation is used to override an attribute mapping inherited from a mapped superclass or an embeddable.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-attributeoverrides]]
|
||||
==== `@AttributeOverrides`
|
||||
|
||||
|
@ -75,6 +79,8 @@ See the <<chapters/query/native/Native.adoc#sql-composite-key-entity-association
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/ConstructorResult.html[`@ConstructorResult`] annotation is used in conjunction with the <<annotations-jpa-sqlresultsetmapping>> annotations to map columns of a given SELECT query to a certain object constructor.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-convert]]
|
||||
==== `@Convert`
|
||||
|
||||
|
@ -176,11 +182,15 @@ See the <<chapters/domain/basic_types.adoc#basic-enums-Enumerated, `@Enumerated`
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/ExcludeDefaultListeners.html[`@ExcludeDefaultListeners`] annotation is used to specify that the current annotated entity skips the invocation of any default listener.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-excludesuperclasslisteners]]
|
||||
==== `@ExcludeSuperclassListeners`
|
||||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/ExcludeSuperclassListeners.html[`@ExcludeSuperclassListeners`] annotation is used to specify that the current annotated entity skips the invocation of listeners declared by its superclass.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-fieldresult]]
|
||||
==== `@FieldResult`
|
||||
|
||||
|
@ -225,6 +235,8 @@ See the <<chapters/domain/identifiers.adoc#identifiers-composite-nonaggregated,C
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/Index.html[`@Index`] annotation is used by the automated schema generation tool to create a database index.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-inheritance]]
|
||||
==== `@Inheritance`
|
||||
|
||||
|
@ -244,6 +256,8 @@ See the <<chapters/domain/associations.adoc#associations-many-to-one-example,`@M
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/JoinColumns.html[`@JoinColumns`] annotation is used to group multiple <<annotations-jpa-joincolumn>> annotations, which are used when mapping entity association or an embeddable collection using a composite identifier
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-jointable]]
|
||||
==== `@JoinTable`
|
||||
|
||||
|
@ -284,11 +298,15 @@ See the <<chapters/domain/collections.adoc#collections-map-unidirectional-exampl
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/MapKeyClass.html[`@MapKeyClass`] annotation is used to specify the type of the map key of a `java.util.Map` associations.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-mapkeycolumn]]
|
||||
==== `@MapKeyColumn`
|
||||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/MapKeyColumn.html[`@MapKeyColumn`] annotation is used to specify the database column which stores the key of a `java.util.Map` association for which the map key is a basic type.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-mapkeyenumerated]]
|
||||
==== `@MapKeyEnumerated`
|
||||
|
||||
|
@ -309,6 +327,8 @@ See the <<chapters/domain/collections.adoc#collections-map-value-type-entity-key
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/MapKeyJoinColumns.html[`@MapKeyJoinColumns`] annotation is used to group several <<annotations-jpa-mapkeyjoincolumn>> mappings when the `java.util.Map` association key uses a composite identifier.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-mapkeytemporal]]
|
||||
==== `@MapKeyTemporal`
|
||||
|
||||
|
@ -373,6 +393,8 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/NamedQueries.html[`@Na
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/NamedQuery.html[`@NamedQuery`] annotation is used to specify a JPQL query that can be retrieved later by its name.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-namedstoredprocedurequeries]]
|
||||
==== `@NamedStoredProcedureQueries`
|
||||
|
||||
|
@ -383,11 +405,15 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/NamedStoredProcedureQu
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/NamedStoredProcedureQuery.html[`@NamedStoredProcedureQuery`] annotation is used to specify a stored procedure query that can be retrieved later by its name.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-namedsubgraph]]
|
||||
==== `@NamedSubgraph`
|
||||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/NamedSubgraph.html[`@NamedSubgraph`] annotation used to specify a subgraph in an Entity Graph.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-onetomany]]
|
||||
==== `@OneToMany`
|
||||
|
||||
|
@ -421,6 +447,8 @@ See the <<chapters/domain/collections.adoc#collections-unidirectional-ordered-li
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/PersistenceContext.html[`@PersistenceContext`] annotation is used to specify the `EntityManager` that needs to be injected as a dependency.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-persistencecontexts]]
|
||||
==== `@PersistenceContexts`
|
||||
|
||||
|
@ -431,11 +459,15 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/PersistenceContexts.ht
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/PersistenceProperty.html[`@PersistenceProperty`] annotation is used by the <<annotations-jpa-persistencecontext>> annotation to declare JPA provider properties that are passed to the underlying container when the `EntityManager` instance is created.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-persistenceunit]]
|
||||
==== `@PersistenceUnit`
|
||||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/PersistenceUnit.html[`@PersistenceUnit`] annotation is used to specify the `EntityManagerFactory` that needs to be injected as a dependency.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-persistenceunits]]
|
||||
==== `@PersistenceUnits`
|
||||
|
||||
|
@ -508,6 +540,8 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/PrimaryKeyJoinColumns.
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/QueryHint.html[`@QueryHint`] annotation is used to specify a JPA provider hint used by a `@NamedQuery` or a `@NamedNativeQuery` annotation.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-secondarytable]]
|
||||
==== `@SecondaryTable`
|
||||
|
||||
|
@ -525,6 +559,8 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/SecondaryTables.html[`
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/SequenceGenerator.html[`@SequenceGenerator`] annotation is used to specify the database sequence used by the identifier generator of the current annotated entity.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-sqlresultsetmapping]]
|
||||
==== `@SqlResultSetMapping`
|
||||
|
||||
|
@ -542,6 +578,8 @@ The http://docs.oracle.com/javaee/7/api/javax/persistence/SqlResultSetMappings.h
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/StoredProcedureParameter.html[`@StoredProcedureParameter`] annotation is used to specify a parameter of a <<annotations-jpa-namedstoredprocedurequery>>.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-table]]
|
||||
==== `@Table`
|
||||
|
||||
|
@ -554,6 +592,8 @@ See the <<chapters/query/native/Native.adoc#sql-custom-crud-secondary-table-exam
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/TableGenerator.html[`@TableGenerator`] annotation is used to specify the database table used by the identity generator of the current annotated entity.
|
||||
|
||||
//TODO: Add example
|
||||
|
||||
[[annotations-jpa-temporal]]
|
||||
==== `@Temporal`
|
||||
|
||||
|
@ -573,6 +613,8 @@ See the <<chapters/events/Events.adoc#events-jpa-callbacks-example, `@Transient`
|
|||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/UniqueConstraint.html[`@UniqueConstraint`] annotation is used to specify a unique constraint to be included by the automated schema generator for the primary or secondary table associated with the current annotated entity.
|
||||
|
||||
See the <<chapters/schema/Schema.adoc#schema-generation-columns-unique-constraint, Columns unique constraint>> chapter for more info.
|
||||
|
||||
[[annotations-jpa-version]]
|
||||
==== `@Version`
|
||||
|
||||
|
|
|
@ -159,3 +159,43 @@ include::{sourcedir}/ColumnDefaultTest.java[tag=schema-generation-column-default
|
|||
include::{extrasdir}/schema-generation-column-default-value-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[schema-generation-columns-unique-constraint]]
|
||||
=== Columns unique constraint
|
||||
|
||||
The http://docs.oracle.com/javaee/7/api/javax/persistence/UniqueConstraint.html[`@UniqueConstraint`] annotation is used to specify a unique constraint to be included by the automated schema generator for the primary or secondary table associated with the current annotated entity.
|
||||
|
||||
Considering the following entity mapping, Hibernate generates the unique constraint DDL when creating the database schema:
|
||||
|
||||
[[schema-generation-columns-unique-constraint-mapping-example]]
|
||||
.`@UniqueConstraint` mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/UniqueConstraintTest.java[tag=schema-generation-columns-unique-constraint-mapping-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/schema-generation-columns-unique-constraint-mapping-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
With the `uk_book_title_author` unique constraint in place,
|
||||
it's no longer possible to add two books with the same title and for the same author.
|
||||
|
||||
[[schema-generation-columns-unique-constraint-persist-example]]
|
||||
.`@UniqueConstraintTest` persist example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/UniqueConstraintTest.java[tag=schema-generation-columns-unique-constraint-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/schema-generation-columns-unique-constraint-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
The second INSERT statement fails because of the unique coonstraint violation.
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
create table author (
|
||||
id bigint not null,
|
||||
firstName varchar(255),
|
||||
lastName varchar(255),
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
create table book (
|
||||
id bigint not null,
|
||||
title varchar(255),
|
||||
author_id bigint,
|
||||
primary key (id)
|
||||
)
|
||||
|
||||
alter table book
|
||||
add constraint uk_book_title_author
|
||||
unique (title, author_id)
|
||||
|
||||
alter table book
|
||||
add constraint fk_book_author_id
|
||||
foreign key (author_id)
|
||||
references author
|
|
@ -0,0 +1,35 @@
|
|||
insert
|
||||
into
|
||||
author
|
||||
(firstName, lastName, id)
|
||||
values
|
||||
(?, ?, ?)
|
||||
|
||||
-- binding parameter [1] as [VARCHAR] - [Vlad]
|
||||
-- binding parameter [2] as [VARCHAR] - [Mihalcea]
|
||||
-- binding parameter [3] as [BIGINT] - [1]
|
||||
|
||||
insert
|
||||
into
|
||||
book
|
||||
(author_id, title, id)
|
||||
values
|
||||
(?, ?, ?)
|
||||
|
||||
-- binding parameter [1] as [BIGINT] - [1]
|
||||
-- binding parameter [2] as [VARCHAR] - [High-Performance Java Persistence]
|
||||
-- binding parameter [3] as [BIGINT] - [2]
|
||||
|
||||
insert
|
||||
into
|
||||
book
|
||||
(author_id, title, id)
|
||||
values
|
||||
(?, ?, ?)
|
||||
|
||||
-- binding parameter [1] as [BIGINT] - [1]
|
||||
-- binding parameter [2] as [VARCHAR] - [High-Performance Java Persistence]
|
||||
-- binding parameter [3] as [BIGINT] - [3]
|
||||
|
||||
-- SQL Error: 23505, SQLState: 23505
|
||||
-- Unique index or primary key violation: "UK_BOOK_TITLE_AUTHOR_INDEX_1 ON PUBLIC.BOOK(TITLE, AUTHOR_ID) VALUES ( /* key:1 */ 3, 'High-Performance Java Persistence', 1)";
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* 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 javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
import org.hibernate.annotations.DynamicInsert;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.util.ExceptionUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
|
||||
public class UniqueConstraintTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Book.class,
|
||||
Author.class,
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
//tag::schema-generation-columns-unique-constraint-persist-example[]
|
||||
Author _author = doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Author author = new Author();
|
||||
author.setFirstName( "Vlad" );
|
||||
author.setLastName( "Mihalcea" );
|
||||
entityManager.persist( author );
|
||||
|
||||
Book book = new Book();
|
||||
book.setTitle( "High-Performance Java Persistence" );
|
||||
book.setAuthor( author );
|
||||
entityManager.persist( book );
|
||||
|
||||
return author;
|
||||
} );
|
||||
|
||||
try {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Book book = new Book();
|
||||
book.setTitle( "High-Performance Java Persistence" );
|
||||
book.setAuthor( _author );
|
||||
entityManager.persist( book );
|
||||
} );
|
||||
}
|
||||
catch (Exception expected) {
|
||||
assertNotNull( ExceptionUtil.findCause( expected, ConstraintViolationException.class ) );
|
||||
}
|
||||
//end::schema-generation-columns-unique-constraint-persist-example[]
|
||||
}
|
||||
|
||||
//tag::schema-generation-columns-unique-constraint-mapping-example[]
|
||||
@Entity
|
||||
@Table(
|
||||
name = "book",
|
||||
uniqueConstraints = @UniqueConstraint(
|
||||
name = "uk_book_title_author",
|
||||
columnNames = {
|
||||
"title",
|
||||
"author_id"
|
||||
}
|
||||
)
|
||||
)
|
||||
public static class Book {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String title;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(
|
||||
name = "author_id",
|
||||
foreignKey = @ForeignKey(name = "fk_book_author_id")
|
||||
)
|
||||
private Author author;
|
||||
|
||||
//Getter and setters omitted for brevity
|
||||
//end::schema-generation-columns-unique-constraint-mapping-example[]
|
||||
|
||||
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 Author getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public void setAuthor(Author author) {
|
||||
this.author = author;
|
||||
}
|
||||
|
||||
//tag::schema-generation-columns-unique-constraint-mapping-example[]
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "author")
|
||||
public static class Author {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
//Getter and setters omitted for brevity
|
||||
//end::schema-generation-columns-unique-constraint-mapping-example[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
//tag::schema-generation-columns-unique-constraint-mapping-example[]
|
||||
}
|
||||
//end::schema-generation-columns-unique-constraint-mapping-example[]
|
||||
}
|
|
@ -13,7 +13,6 @@ hibernate.connection.password @jdbc.pass@
|
|||
|
||||
hibernate.connection.pool_size 5
|
||||
|
||||
hibernate.show_sql true
|
||||
hibernate.format_sql true
|
||||
hibernate.max_fetch_depth 5
|
||||
|
||||
|
|
|
@ -42,6 +42,22 @@ public class ExceptionUtil {
|
|||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific cause.
|
||||
*
|
||||
* @param t exception
|
||||
* @param causeClass cause type
|
||||
*
|
||||
* @return exception root cause
|
||||
*/
|
||||
public static Throwable findCause(Throwable t, Class<? extends Throwable> causeClass) {
|
||||
Throwable cause = t.getCause();
|
||||
if ( cause != null && !causeClass.equals( cause.getClass() ) ) {
|
||||
return ( cause != t ) ? findCause( cause, causeClass ) : null;
|
||||
}
|
||||
return cause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Was the given exception caused by a SQL lock timeout?
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue