HHH-15664 Fix array section in documentation

This commit is contained in:
Christian Beikov 2023-03-13 11:32:37 +01:00
parent bf2716ac5c
commit 713be8eba6
5 changed files with 121 additions and 32 deletions

View File

@ -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 <<collections-array-as-basic,previous section>>.
Such mappings are not normal and beyond the scope of this documentation. The best way to map such a situation
is using an <<basic-jpa-convert,AttributeConverter>>.
[[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 <<basic-jpa-convert,AttributeConverter>> 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

View File

@ -0,0 +1,5 @@
CREATE TABLE Person (
id BIGINT NOT NULL,
phones VARCHAR(255) ARRAY,
PRIMARY KEY ( id )
)

View File

@ -1,5 +0,0 @@
CREATE TABLE Person (
id BIGINT NOT NULL ,
phones VARBINARY(255) ,
PRIMARY KEY ( id )
)

View File

@ -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[]
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<String> 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<String> 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<String> phones;
//Getters and setters are omitted for brevity
//end::collections-as-basic-example[]
public Person() {
}
public Person(Long id) {
this.id = id;
}
public List<String> getPhones() {
return phones;
}
public void setPhones(List<String> phones) {
this.phones = phones;
}
//tag::collections-as-basic-example[]
}
//end::collections-as-basic-example[]
}