diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/MutableNaturalIdMapping.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/MutableNaturalIdMapping.java deleted file mode 100644 index b969be1fa6..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/MutableNaturalIdMapping.java +++ /dev/null @@ -1,11 +0,0 @@ -@Entity -public class Person { - - @Id - private Integer id; - - @NaturalId( mutable = true ) - private String ssn; - - ... -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/MutableNaturalIdSynchronization.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/MutableNaturalIdSynchronization.java deleted file mode 100644 index e075f6f09e..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/MutableNaturalIdSynchronization.java +++ /dev/null @@ -1,16 +0,0 @@ -Session session=...; - -Person person = session.bySimpleNaturalId( Person.class ).load( "123-45-6789" ); -person.setSsn( "987-65-4321" ); - -... - -// returns null! -person = session.bySimpleNaturalId( Person.class ) - .setSynchronizationEnabled( false ) - .load( "987-65-4321" ); - -// returns correctly! -person = session.bySimpleNaturalId( Person.class ) - .setSynchronizationEnabled( true ) - .load( "987-65-4321" ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NaturalIdCaching.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NaturalIdCaching.java deleted file mode 100644 index a86148ad73..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NaturalIdCaching.java +++ /dev/null @@ -1,12 +0,0 @@ -@Entity -@NaturalIdCache -public class Company { - - @Id - private Integer id; - - @NaturalId - private String taxIdentifier; - - ... -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NaturalIdLoadAccessUsage.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NaturalIdLoadAccessUsage.java deleted file mode 100644 index 0386937963..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NaturalIdLoadAccessUsage.java +++ /dev/null @@ -1,15 +0,0 @@ -Session session = ...; - -Company company = session.byNaturalId( Company.class ) - .using( "taxIdentifier","abc-123-xyz" ) - .load(); - -PostalCarrier carrier = session.byNaturalId( PostalCarrier.class ) - .using( "postalCode",new PostalCode(... ) ) - .load(); - -Department department = ...; -Course course = session.byNaturalId( Course.class ) - .using( "department",department ) - .using( "code","101" ) - .load(); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NonSimpleNaturalIdMapping.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NonSimpleNaturalIdMapping.java deleted file mode 100644 index 1d3d7a5b87..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/NonSimpleNaturalIdMapping.java +++ /dev/null @@ -1,15 +0,0 @@ -@Entity -public class Course { - - @Id - private Integer id; - - @NaturalId - @ManyToOne - private Department department; - - @NaturalId - private String code; - - ... -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleBasicNaturalIdMapping.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleBasicNaturalIdMapping.java deleted file mode 100644 index 373da20203..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleBasicNaturalIdMapping.java +++ /dev/null @@ -1,11 +0,0 @@ -@Entity -public class Company { - - @Id - private Integer id; - - @NaturalId - private String taxIdentifier; - - ... -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleCompositeNaturalIdMapping.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleCompositeNaturalIdMapping.java deleted file mode 100644 index 2487399266..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleCompositeNaturalIdMapping.java +++ /dev/null @@ -1,18 +0,0 @@ -@Entity -public class PostalCarrier { - - @Id - private Integer id; - - @NaturalId - @Embedded - private PostalCode postalCode; - - ... - -} - -@Embeddable -public class PostalCode { - ... -} diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleNaturalIdLoadAccessUsage.java b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleNaturalIdLoadAccessUsage.java deleted file mode 100644 index e7b8e5778a..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/natural_id/SimpleNaturalIdLoadAccessUsage.java +++ /dev/null @@ -1,7 +0,0 @@ -Session session = ...; - -Company company = session.bySimpleNaturalId( Company.class ) - .load( "abc-123-xyz" ); - -PostalCarrier carrier = session.bySimpleNaturalId( PostalCarrier.class ) - .load( new PostalCode(... ) ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/natural_id.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/natural_id.adoc index b383725719..35bc3600a9 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/natural_id.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/natural_id.adoc @@ -1,6 +1,7 @@ [[naturalid]] === Natural Ids -:sourcedir: extras +:sourcedir: ../../../../../test/java/org/hibernate/userguide/mapping/identifier +:extrasdir: extras Natural ids represent domain model unique identifiers that have a meaning in the real world too. Even if a natural id does not make a good primary key (surrogate keys being usually preferred), it's still useful to tell Hibernate about it. @@ -9,29 +10,33 @@ As we will see later, Hibernate provides a dedicated, efficient API for loading [[naturalid-mapping]] ==== Natural Id Mapping -Natural ids are defined in terms of one or more persistent attributes. +Natural ids are defined in terms of on +e or more persistent attributes. +[[naturalid-simple-basic-attribute-mapping-example]] .Natural id using single basic attribute ==== [source,java] ---- -include::{sourcedir}/natural_id/SimpleBasicNaturalIdMapping.java[] +include::{sourcedir}/SimpleNaturalIdTest.java[tags=naturalid-simple-basic-attribute-mapping-example,indent=0] ---- ==== +[[naturalid-single-embedded-attribute-mapping-example]] .Natural id using single embedded attribute ==== [source,java] ---- -include::{sourcedir}/natural_id/SimpleCompositeNaturalIdMapping.java[] +include::{sourcedir}/CompositeNaturalIdTest.java[tags=naturalid-single-embedded-attribute-mapping-example,indent=0] ---- ==== +[[naturalid-multiple-attribute-mapping-example]] .Natural id using multiple persistent attributes ==== [source,java] ---- -include::{sourcedir}/natural_id/NonSimpleNaturalIdMapping.java[] +include::{sourcedir}/MultipleNaturalIdTest.java[tags=naturalid-multiple-attribute-mapping-example,indent=0] ---- ==== @@ -46,11 +51,22 @@ This is represented by the `org.hibernate.NaturalIdLoadAccess` contract obtained If the entity does not define a natural id, trying to load an entity by its natural id will throw an exception. ==== +[[naturalid-load-access-example]] .Using NaturalIdLoadAccess ==== [source,java] ---- -include::{sourcedir}/natural_id/NaturalIdLoadAccessUsage.java[] +include::{sourcedir}/SimpleNaturalIdTest.java[tags=naturalid-load-access-example,indent=0] +---- + +[source,java] +---- +include::{sourcedir}/CompositeNaturalIdTest.java[tags=naturalid-load-access-example,indent=0] +---- + +[source,java] +---- +include::{sourcedir}/MultipleNaturalIdTest.java[tags=naturalid-load-access-example,indent=0] ---- ==== @@ -68,17 +84,26 @@ We will discuss the last method available on NaturalIdLoadAccess ( `setSynchroni Because the `Company` and `PostalCarrier` entities define "simple" natural ids, we can load them as follows: -.Using SimpleNaturalIdLoadAccess +[[naturalid-simple-load-access-example]] +.Loading by simple natural id ==== [source,java] ---- -include::{sourcedir}/natural_id/SimpleNaturalIdLoadAccessUsage.java[] +include::{sourcedir}/SimpleNaturalIdTest.java[tags=naturalid-simple-load-access-example,indent=0] +---- + +[source,java] +---- +include::{sourcedir}/CompositeNaturalIdTest.java[tags=naturalid-simple-load-access-example,indent=0] ---- ==== -Here we see the use of the `org.hibernate.SimpleNaturalIdLoadAccess` contract, obtained via `Session#bySimpleNaturalId(). +Here we see the use of the `org.hibernate.SimpleNaturalIdLoadAccess` contract, +obtained via `Session#bySimpleNaturalId(). + `SimpleNaturalIdLoadAccess` is similar to `NaturalIdLoadAccess` except that it does not define the using method. -Instead, because these "simple" natural ids are defined based on just one attribute we can directly pass the corresponding value of that natural id attribute directly to the `load()` and `getReference()` methods. +Instead, because these _simple_ natural ids are defined based on just one attribute we can directly pass +the corresponding natural id attribute value directly to the `load()` and `getReference()` methods. [NOTE] ==== @@ -90,18 +115,21 @@ If the entity does not define a natural id, or if the natural id is not of a "si A natural id may be mutable or immutable. By default the `@NaturalId` annotation marks an immutable natural id attribute. An immutable natural id is expected to never change its value. + If the value(s) of the natural id attribute(s) change, `@NaturalId(mutable=true)` should be used instead. -.Mutable natural id +[[naturalid-mutable-mapping-example]] +.Mutable natural id mapping ==== [source,java] ---- -include::{sourcedir}/natural_id/MutableNaturalIdMapping.java[] +include::{sourcedir}/MutableNaturalIdTest.java[tags=naturalid-mutable-mapping-example,indent=0] ---- ==== Within the Session, Hibernate maintains a mapping from natural id values to entity identifiers (PK) values. If natural ids values changed, it is possible for this mapping to become out of date until a flush occurs. + To work around this condition, Hibernate will attempt to discover any such pending changes and adjust them when the `load()` or `getReference()` methods are executed. To be clear: this is only pertinent for mutable natural ids. @@ -112,11 +140,12 @@ If an application is certain that none of its mutable natural ids already associ This will force Hibernate to circumvent the checking of mutable natural ids. ==== +[[naturalid-mutable-synchronized-example]] .Mutable natural id synchronization use-case ==== [source,java] ---- -include::{sourcedir}/natural_id/MutableNaturalIdSynchronization.java[] +include::{sourcedir}/MutableNaturalIdTest.java[tags=naturalid-mutable-synchronized-example,indent=0] ---- ==== @@ -127,6 +156,6 @@ Not only can this NaturalId-to-PK resolution be cached in the Session, but we ca ==== [source,java] ---- -include::{sourcedir}/natural_id/NaturalIdCaching.java[] +include::{sourcedir}/CacheableNaturalIdTest.java[tags=naturalid-cacheable-mapping-example,indent=0] ---- ==== \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc index 502376b579..00c665632d 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc @@ -48,6 +48,8 @@ According to JPA, the valid types for these attributes are limited to: * `long` or `Long` * `java.sql.Timestamp` +However, Hibernate allows you to use even Java 8 Date/Time types, such as `Instant`. + [[locking-optimistic-version-example]] .`@Version` annotation mapping ==== diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/CacheableNaturalIdTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/CacheableNaturalIdTest.java new file mode 100644 index 0000000000..1df8be9bdc --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/CacheableNaturalIdTest.java @@ -0,0 +1,122 @@ +/* + * 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 . + */ +package org.hibernate.userguide.mapping.identifier; + +import java.util.Map; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.Session; +import org.hibernate.annotations.NaturalId; +import org.hibernate.annotations.NaturalIdCache; +import org.hibernate.cache.ehcache.EhCacheRegionFactory; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +public class CacheableNaturalIdTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Book.class + }; + } + + @Override + @SuppressWarnings( "unchecked" ) + protected void addConfigOptions(Map options) { + options.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, Boolean.TRUE.toString() ); + options.put( AvailableSettings.CACHE_REGION_FACTORY, EhCacheRegionFactory.class.getName() ); + options.put( AvailableSettings.USE_QUERY_CACHE, Boolean.TRUE.toString() ); + options.put( AvailableSettings.GENERATE_STATISTICS, Boolean.TRUE.toString() ); + options.put( AvailableSettings.CACHE_REGION_PREFIX, "" ); + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + Book book = new Book(); + book.setId( 1L ); + book.setTitle( "High-Performance Java Persistence" ); + book.setAuthor( "Vlad Mihalcea" ); + book.setIsbn( "978-9730228236" ); + + entityManager.persist( book ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::naturalid-cacheable-load-access-example[] + Book book = entityManager + .unwrap(Session.class) + .bySimpleNaturalId( Book.class ) + .load( "978-9730228236" ); + //end::naturalid-cacheable-load-access-example[] + + assertEquals("High-Performance Java Persistence", book.getTitle()); + } ); + } + + //tag::naturalid-cacheable-mapping-example[] + @Entity(name = "Book") + @NaturalIdCache + public static class Book { + + @Id + private Long id; + + private String title; + + private String author; + + @NaturalId + private String isbn; + + //Getters and setters are omitted for brevity + //end::naturalid-cacheable-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 String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + //tag::naturalid-cacheable-mapping-example[] + } + //end::naturalid-cacheable-mapping-example[] +} diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/CompositeNaturalIdTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/CompositeNaturalIdTest.java new file mode 100644 index 0000000000..d1a48f4603 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/CompositeNaturalIdTest.java @@ -0,0 +1,193 @@ +/* + * 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 . + */ +package org.hibernate.userguide.mapping.identifier; + +import java.io.Serializable; +import java.util.Objects; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.Session; +import org.hibernate.annotations.NaturalId; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +public class CompositeNaturalIdTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Book.class + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + Book book = new Book(); + book.setId( 1L ); + book.setTitle( "High-Performance Java Persistence" ); + book.setAuthor( "Vlad Mihalcea" ); + book.setIsbn( new Isbn( + "973022823X", + "978-9730228236" + ) ); + + entityManager.persist( book ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::naturalid-simple-load-access-example[] + + Book book = entityManager + .unwrap(Session.class) + .bySimpleNaturalId( Book.class ) + .load( + new Isbn( + "973022823X", + "978-9730228236" + ) + ); + //end::naturalid-simple-load-access-example[] + + assertEquals("High-Performance Java Persistence", book.getTitle()); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::naturalid-load-access-example[] + + Book book = entityManager + .unwrap(Session.class) + .byNaturalId( Book.class ) + .using( + "isbn", + new Isbn( + "973022823X", + "978-9730228236" + ) ) + .load(); + //end::naturalid-load-access-example[] + + assertEquals("High-Performance Java Persistence", book.getTitle()); + } ); + } + + //tag::naturalid-single-embedded-attribute-mapping-example[] + @Entity(name = "Book") + public static class Book { + + @Id + private Long id; + + private String title; + + private String author; + + @NaturalId + @Embedded + private Isbn isbn; + + //Getters and setters are omitted for brevity + //end::naturalid-single-embedded-attribute-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 String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Isbn getIsbn() { + return isbn; + } + + public void setIsbn(Isbn isbn) { + this.isbn = isbn; + } + //tag::naturalid-single-embedded-attribute-mapping-example[] + } + + @Embeddable + public static class Isbn implements Serializable { + + private String isbn10; + + private String isbn13; + + //Getters and setters are omitted for brevity + //end::naturalid-single-embedded-attribute-mapping-example[] + + public Isbn() { + } + + public Isbn(String isbn10, String isbn13) { + this.isbn10 = isbn10; + this.isbn13 = isbn13; + } + + public String getIsbn10() { + return isbn10; + } + + public void setIsbn10(String isbn10) { + this.isbn10 = isbn10; + } + + public String getIsbn13() { + return isbn13; + } + + public void setIsbn13(String isbn13) { + this.isbn13 = isbn13; + } + + //tag::naturalid-single-embedded-attribute-mapping-example[] + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Isbn isbn = (Isbn) o; + return Objects.equals( isbn10, isbn.isbn10 ) && + Objects.equals( isbn13, isbn.isbn13 ); + } + + @Override + public int hashCode() { + return Objects.hash( isbn10, isbn13 ); + } + } + //end::naturalid-single-embedded-attribute-mapping-example[] +} diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/MultipleNaturalIdTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/MultipleNaturalIdTest.java new file mode 100644 index 0000000000..c68bd26197 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/MultipleNaturalIdTest.java @@ -0,0 +1,185 @@ +/* + * 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 . + */ +package org.hibernate.userguide.mapping.identifier; + +import java.io.Serializable; +import java.util.Objects; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +import org.hibernate.Session; +import org.hibernate.annotations.NaturalId; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +public class MultipleNaturalIdTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Book.class, + Publisher.class + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + Publisher publisher = new Publisher(); + publisher.setId( 1L ); + publisher.setName( "Amazon" ); + entityManager.persist( publisher ); + + Book book = new Book(); + book.setId( 1L ); + book.setTitle( "High-Performance Java Persistence" ); + book.setAuthor( "Vlad Mihalcea" ); + book.setProductNumber( "973022823X" ); + book.setPublisher( publisher ); + + entityManager.persist( book ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + Publisher publisher = entityManager.getReference( Publisher.class, 1L ); + //tag::naturalid-load-access-example[] + + Book book = entityManager + .unwrap(Session.class) + .byNaturalId( Book.class ) + .using("productNumber", "973022823X") + .using("publisher", publisher) + .load(); + //end::naturalid-load-access-example[] + + assertEquals("High-Performance Java Persistence", book.getTitle()); + } ); + } + + //tag::naturalid-multiple-attribute-mapping-example[] + @Entity(name = "Book") + public static class Book { + + @Id + private Long id; + + private String title; + + private String author; + + @NaturalId + private String productNumber; + + @NaturalId + @ManyToOne(fetch = FetchType.LAZY) + private Publisher publisher; + + //Getters and setters are omitted for brevity + //end::naturalid-multiple-attribute-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 String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getProductNumber() { + return productNumber; + } + + public void setProductNumber(String productNumber) { + this.productNumber = productNumber; + } + + public Publisher getPublisher() { + return publisher; + } + + public void setPublisher(Publisher publisher) { + this.publisher = publisher; + } + //tag::naturalid-multiple-attribute-mapping-example[] + } + + @Entity(name = "Publisher") + public static class Publisher implements Serializable { + + @Id + private Long id; + + private String name; + + //Getters and setters are omitted for brevity + //end::naturalid-multiple-attribute-mapping-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; + } + + //tag::naturalid-multiple-attribute-mapping-example[] + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Publisher publisher = (Publisher) o; + return Objects.equals( id, publisher.id ) && + Objects.equals( name, publisher.name ); + } + + @Override + public int hashCode() { + return Objects.hash( id, name ); + } + } + //end::naturalid-multiple-attribute-mapping-example[] +} diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/MutableNaturalIdTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/MutableNaturalIdTest.java new file mode 100644 index 0000000000..174e1be49d --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/MutableNaturalIdTest.java @@ -0,0 +1,120 @@ +/* + * 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 . + */ +package org.hibernate.userguide.mapping.identifier; + +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.Session; +import org.hibernate.annotations.NaturalId; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +/** + * @author Vlad Mihalcea + */ +public class MutableNaturalIdTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Author.class + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + Author author = new Author(); + author.setId( 1L ); + author.setName( "John Doe" ); + author.setEmail( "john@acme.com" ); + + entityManager.persist( author ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::naturalid-mutable-synchronized-example[] + //tag::naturalid-mutable-example[] + Author author = entityManager + .unwrap(Session.class) + .bySimpleNaturalId( Author.class ) + .load( "john@acme.com" ); + //end::naturalid-mutable-example[] + + author.setEmail( "john.doe@acme.com" ); + + assertNull( + entityManager + .unwrap(Session.class) + .bySimpleNaturalId( Author.class ) + .setSynchronizationEnabled( false ) + .load( "john.doe@acme.com" ) + ); + + assertSame( author, + entityManager + .unwrap(Session.class) + .bySimpleNaturalId( Author.class ) + .setSynchronizationEnabled( true ) + .load( "john.doe@acme.com" ) + ); + //end::naturalid-mutable-example[] + + //end::naturalid-mutable-synchronized-example[] + } ); + } + + //tag::naturalid-mutable-mapping-example[] + @Entity(name = "Author") + public static class Author { + + @Id + private Long id; + + private String name; + + @NaturalId(mutable = true) + private String email; + + //Getters and setters are omitted for brevity + //end::naturalid-mutable-mapping-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 getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + //tag::naturalid-mutable-mapping-example[] + } + //end::naturalid-mutable-mapping-example[] +} diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/SimpleNaturalIdTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/SimpleNaturalIdTest.java new file mode 100644 index 0000000000..cd49dc6752 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/identifier/SimpleNaturalIdTest.java @@ -0,0 +1,118 @@ +/* + * 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 . + */ +package org.hibernate.userguide.mapping.identifier; + +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.Session; +import org.hibernate.annotations.NaturalId; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +public class SimpleNaturalIdTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Book.class + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + Book book = new Book(); + book.setId( 1L ); + book.setTitle( "High-Performance Java Persistence" ); + book.setAuthor( "Vlad Mihalcea" ); + book.setIsbn( "978-9730228236" ); + + entityManager.persist( book ); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::naturalid-simple-load-access-example[] + Book book = entityManager + .unwrap(Session.class) + .bySimpleNaturalId( Book.class ) + .load( "978-9730228236" ); + //end::naturalid-simple-load-access-example[] + + assertEquals("High-Performance Java Persistence", book.getTitle()); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::naturalid-load-access-example[] + Book book = entityManager + .unwrap(Session.class) + .byNaturalId( Book.class ) + .using( "isbn", "978-9730228236" ) + .load(); + //end::naturalid-load-access-example[] + + assertEquals("High-Performance Java Persistence", book.getTitle()); + } ); + } + + //tag::naturalid-simple-basic-attribute-mapping-example[] + @Entity(name = "Book") + public static class Book { + + @Id + private Long id; + + private String title; + + private String author; + + @NaturalId + private String isbn; + + //Getters and setters are omitted for brevity + //end::naturalid-simple-basic-attribute-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 String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + //tag::naturalid-simple-basic-attribute-mapping-example[] + } + //end::naturalid-simple-basic-attribute-mapping-example[] +}