discuss mapping embeddables to UDTs or JSON
This commit is contained in:
parent
c76a36a1f2
commit
a4d9c85ba3
|
@ -792,7 +792,7 @@ Let's abandon our analogy right here, before we start calling this basic type a
|
||||||
[[embeddable-objects]]
|
[[embeddable-objects]]
|
||||||
=== Embeddable objects
|
=== Embeddable objects
|
||||||
|
|
||||||
An embeddable object is a Java class whose state maps to multiple columns of a table, but which doesn't itself have a persistent identity.
|
An embeddable object is a Java class whose state maps to multiple columns of a table, but which doesn't have its own persistent identity.
|
||||||
That is, it's a class with mapped attributes, but no `@Id` attribute.
|
That is, it's a class with mapped attributes, but no `@Id` attribute.
|
||||||
|
|
||||||
An embeddable object can only be made persistent by assigning it to the attribute of an entity.
|
An embeddable object can only be made persistent by assigning it to the attribute of an entity.
|
||||||
|
@ -828,7 +828,7 @@ class Name {
|
||||||
An embeddable class must satisfy the same requirements that entity classes satisfy, with the exception that an embeddable class has no `@Id` attribute.
|
An embeddable class must satisfy the same requirements that entity classes satisfy, with the exception that an embeddable class has no `@Id` attribute.
|
||||||
In particular, it must have a constructor with no parameters.
|
In particular, it must have a constructor with no parameters.
|
||||||
|
|
||||||
Alternatively, and embeddable type may be defined as a Java record type:
|
Alternatively, an embeddable type may be defined as a Java record type:
|
||||||
|
|
||||||
[source,java]
|
[source,java]
|
||||||
----
|
----
|
||||||
|
@ -855,6 +855,9 @@ class Author {
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Embeddable types can be nested.
|
||||||
|
That is, an `@Embeddable` class may have an attribute whose type is itself a different `@Embeddable` class.
|
||||||
|
|
||||||
[TIP]
|
[TIP]
|
||||||
// .The `@Embedded` annotation is not required
|
// .The `@Embedded` annotation is not required
|
||||||
====
|
====
|
||||||
|
@ -862,12 +865,16 @@ JPA provides an `@Embedded` annotation to identify an attribute of an entity tha
|
||||||
This annotation is completely optional, and so we don't usually use it.
|
This annotation is completely optional, and so we don't usually use it.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
Usually, embeddable types are stored in a "flattened" format.
|
||||||
|
Their attributes map columns of the table of their parent entity.
|
||||||
|
Later, in <<mapping-embeddables>>, we'll see a couple of different options.
|
||||||
|
|
||||||
An attribute of embeddable type represents a relationship between a Java object with a persistent identity, and a Java object with no persistent identity.
|
An attribute of embeddable type represents a relationship between a Java object with a persistent identity, and a Java object with no persistent identity.
|
||||||
You can think of it as a whole-part relationship.
|
We can think of it as a whole/part relationship.
|
||||||
The embeddable object belongs to the entity, and can't be shared with other entity instances.
|
The embeddable object belongs to the entity, and can't be shared with other entity instances.
|
||||||
|
And it exits for only as long as its parent entity exists.
|
||||||
|
|
||||||
Now we'll discuss a different kind of relationship: a relationship between Java objects that each have their persistent identity and persistence lifecycle.
|
Next we'll discuss a different kind of relationship: a relationship between Java objects that each have their persistent identity and persistence lifecycle.
|
||||||
|
|
||||||
|
|
||||||
[[associations]]
|
[[associations]]
|
||||||
=== Associations
|
=== Associations
|
||||||
|
|
|
@ -653,6 +653,84 @@ InputStream bytes = book.images.getBinaryStream();
|
||||||
|
|
||||||
Of course, the behavior here depends very much on the JDBC driver, and so we really can't promise that this is a sensible thing to do on your database.
|
Of course, the behavior here depends very much on the JDBC driver, and so we really can't promise that this is a sensible thing to do on your database.
|
||||||
|
|
||||||
|
[[mapping-embeddables]]
|
||||||
|
=== Mapping embeddable types to UDTs or to JSON
|
||||||
|
|
||||||
|
There's a couple of alternative ways to represent an embeddable type on the database side.
|
||||||
|
|
||||||
|
[discrete]
|
||||||
|
==== Embeddables as UDTs
|
||||||
|
|
||||||
|
First, a really nice option, at least in the case of Java record types, and for databases which support _user-defined types_ (UDTs), is to define a UDT which represents the record type.
|
||||||
|
Hibernate 6 makes this really easy.
|
||||||
|
Just annotate the record type, or the attribute which holds a reference to it, with the new `@Struct` annotation:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Embeddable
|
||||||
|
@Struct(name="PersonName")
|
||||||
|
record Name(String firstName, String middleName, String lastName) {}
|
||||||
|
----
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Entity
|
||||||
|
class Person {
|
||||||
|
...
|
||||||
|
Name name;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
This results in the following UDT:
|
||||||
|
|
||||||
|
[source,sql]
|
||||||
|
----
|
||||||
|
create type PersonName as (firstName varchar(255), middleName varchar(255), lastName varchar(255))
|
||||||
|
----
|
||||||
|
|
||||||
|
And the `name` column of the `Author` table will have the type `PersonName`.
|
||||||
|
|
||||||
|
[discrete]
|
||||||
|
==== Embeddables to JSON
|
||||||
|
|
||||||
|
A second option that's available is to map the embeddable type to a `JSON` (or `JSONB`) column.
|
||||||
|
Now, this isn't something we would exactly _recommend_ if you're defining a data model from scratch, but it's at least useful for mapping pre-existing tables with JSON-typed columns.
|
||||||
|
Since embeddable types are nestable, we can map some JSON formats this way, and even query JSON properties using HQL.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
At this time, JSON arrays are not supported!
|
||||||
|
====
|
||||||
|
|
||||||
|
To map an attribute of embeddable type to JSON, we must annotate the attribute `@JdbcTypeCode(SqlTypes.JSON)`, instead of annotating the embeddable type.
|
||||||
|
But the embeddable type `Name` should still be annotated `@Embeddable` if we want to query its attributes using HQL.
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Embeddable
|
||||||
|
record Name(String firstName, String middleName, String lastName) {}
|
||||||
|
----
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Entity
|
||||||
|
class Person {
|
||||||
|
...
|
||||||
|
@JdbcTypeCode(SqlTypes.JSON)
|
||||||
|
Name name;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
We also need to add Jackson or an implementation of JSONB—for example, Yasson—to our runtime classpath.
|
||||||
|
To use Jackson we could add this line to our Gradle build:
|
||||||
|
|
||||||
|
[source,groovy]
|
||||||
|
----
|
||||||
|
runtimeOnly 'com.fasterxml.jackson.core:jackson-databind:{jacksonVersion}'
|
||||||
|
----
|
||||||
|
|
||||||
|
Now the `name` column of the `Author` table will have the type `jsonb`, and Hibernate will automatically use Jackson to serialize a `Name` to and from JSON format.
|
||||||
|
|
||||||
[[mapping-formulas]]
|
[[mapping-formulas]]
|
||||||
=== Mapping to formulas
|
=== Mapping to formulas
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue