From 713be8eba6fa08daf2dcd2844ea6b781ea86e627 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 13 Mar 2023 11:32:37 +0100 Subject: [PATCH] HHH-15664 Fix array section in documentation --- .../chapters/domain/collections.adoc | 54 +++++++------ .../collections-array-as-basic-example.sql | 5 ++ .../collections-array-binary-example.sql | 5 -- .../userguide/collections/ArrayTest.java | 8 +- .../userguide/collections/CollectionTest.java | 81 +++++++++++++++++++ 5 files changed, 121 insertions(+), 32 deletions(-) create mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-as-basic-example.sql delete mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-binary-example.sql create mode 100644 documentation/src/test/java/org/hibernate/userguide/collections/CollectionTest.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc index 597d3933bf..eaebe2aec6 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/collections.adoc @@ -1049,40 +1049,34 @@ include::{extrasdir}/collections-map-bidirectional-example.sql[] When discussing arrays, it is important to understand the distinction between SQL array types and Java arrays that are mapped as part of the application's domain model. Not all databases implement the SQL-99 ARRAY type and, for this reason, -Hibernate doesn't support native database array types. +the SQL type used by Hibernate for arrays varies depending on the database support. -Hibernate does support the mapping of arrays in the Java domain model - conceptually the same as mapping a List. -However, it is important to realize that it is impossible for Hibernate to offer lazy-loading for arrays of entities and, for this reason, -it is strongly recommended to map a "collection" of entities using a List rather than an array. +NOTE: It is impossible for Hibernate to offer lazy-loading for arrays of entities and, for this reason, +it is strongly recommended to map a "collection" of entities using a List or Set rather than an array. -[[collections-array-binary]] -==== Arrays as binary +[[collections-array-as-basic]] +==== [[collections-array-binary]] Arrays as basic value type -By default, Hibernate will choose a BINARY type, as supported by the current `Dialect`. +By default, Hibernate will choose a type for the array based on `Dialect.getPreferredSqlTypeCodeForArray()`. +Prior to Hibernate 6.1, the default was to always use the BINARY type, as supported by the current `Dialect`, +but now, Hibernate will leverage the native array data types if possible. -[[collections-array-binary-example]] -.Arrays stored as binary +[[collections-array-binary-example]] To force the BINARY type, the persistent attribute has to be annotated with `@JdbcTypeCode(SqlTypes.VARBINARY)`. + +[[collections-array-as-basic-example]] +.Arrays stored as SQL array ==== [source,java] ---- -include::{example-dir-collection-doc}/ArrayTest.java[tags=collections-array-binary-example,indent=0] +include::{example-dir-collection-doc}/ArrayTest.java[tags=collections-array-as-basic-example,indent=0] ---- [source,sql] ---- -include::{extrasdir}/collections-array-binary-example.sql[] +include::{extrasdir}/collections-array-as-basic-example.sql[] ---- ==== -[NOTE] -==== -If you want to map arrays such as `String[]` or `int[]` to database-specific array types like PostgreSQL `integer[]` or `text[]`, -you need to write a custom Hibernate Type. - -Check out https://vladmihalcea.com/how-to-map-java-and-sql-arrays-with-jpa-and-hibernate/[this article] for an example of how to write -such a custom Hibernate Type. -==== - [[collections-as-basic]] ==== Collections as basic value type @@ -1090,10 +1084,24 @@ Notice how all the previous examples explicitly mark the collection attribute as `@OneToMany` or `@ManyToMany`. Attributes of collection or array type without any of those annotations are considered basic types and by -default mapped to the database as VARBINARY. +default mapped like basic arrays as depicted in the <>. -Such mappings are not normal and beyond the scope of this documentation. The best way to map such a situation -is using an <>. +[[collections-as-basic-example]] +.Collections stored as SQL array +==== +[source,java] +---- +include::{example-dir-collection-doc}/CollectionTest.java[tags=collections-as-basic-example,indent=0] +---- + +[source,sql] +---- +include::{extrasdir}/collections-array-as-basic-example.sql[] +---- +==== + +Prior to Hibernate 6.1, it was common to use an <> to map the elements +into e.g. a comma separated list which is still a viable option. Just note that it is not required anymore. [[ex-collections-comma-delimited-list]] .Comma delimited collection diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-as-basic-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-as-basic-example.sql new file mode 100644 index 0000000000..6b6a789148 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-as-basic-example.sql @@ -0,0 +1,5 @@ +CREATE TABLE Person ( + id BIGINT NOT NULL, + phones VARCHAR(255) ARRAY, + PRIMARY KEY ( id ) +) \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-binary-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-binary-example.sql deleted file mode 100644 index 500393bdaa..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/collections/collections-array-binary-example.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE Person ( - id BIGINT NOT NULL , - phones VARBINARY(255) , - PRIMARY KEY ( id ) -) \ No newline at end of file diff --git a/documentation/src/test/java/org/hibernate/userguide/collections/ArrayTest.java b/documentation/src/test/java/org/hibernate/userguide/collections/ArrayTest.java index 550c9a51c8..5cfeb67501 100644 --- a/documentation/src/test/java/org/hibernate/userguide/collections/ArrayTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/collections/ArrayTest.java @@ -45,7 +45,7 @@ public class ArrayTest extends BaseEntityManagerFunctionalTestCase { }); } - //tag::collections-array-binary-example[] + //tag::collections-array-as-basic-example[] @Entity(name = "Person") public static class Person { @@ -56,7 +56,7 @@ public class ArrayTest extends BaseEntityManagerFunctionalTestCase { //Getters and setters are omitted for brevity - //end::collections-array-binary-example[] + //end::collections-array-as-basic-example[] public Person() { } @@ -72,7 +72,7 @@ public class ArrayTest extends BaseEntityManagerFunctionalTestCase { public void setPhones(String[] phones) { this.phones = phones; } - //tag::collections-array-binary-example[] + //tag::collections-array-as-basic-example[] } - //end::collections-array-binary-example[] + //end::collections-array-as-basic-example[] } diff --git a/documentation/src/test/java/org/hibernate/userguide/collections/CollectionTest.java b/documentation/src/test/java/org/hibernate/userguide/collections/CollectionTest.java new file mode 100644 index 0000000000..1a146719a7 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/collections/CollectionTest.java @@ -0,0 +1,81 @@ +/* + * 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.collections; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Christian Beikov + */ +public class CollectionTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class + }; + } + + @Test + public void testLifecycle() { + doInJPA(this::entityManagerFactory, entityManager -> { + Person person = new Person(1L); + List phones = new ArrayList<>(); + phones.add( "028-234-9876" ); + phones.add( "072-122-9876" ); + person.setPhones(phones); + entityManager.persist(person); + }); + doInJPA(this::entityManagerFactory, entityManager -> { + Person person = entityManager.find(Person.class, 1L); + List phones = new ArrayList<>(); + phones.add( "072-122-9876" ); + person.setPhones(phones); + }); + } + + //tag::collections-as-basic-example[] + @Entity(name = "Person") + public static class Person { + + @Id + private Long id; + + private List phones; + + //Getters and setters are omitted for brevity + + //end::collections-as-basic-example[] + + public Person() { + } + + public Person(Long id) { + this.id = id; + } + + public List getPhones() { + return phones; + } + + public void setPhones(List phones) { + this.phones = phones; + } + //tag::collections-as-basic-example[] + } + //end::collections-as-basic-example[] +}