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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
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]
|
||||
----
|
||||
|
@ -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]
|
||||
// .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.
|
||||
====
|
||||
|
||||
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.
|
||||
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.
|
||||
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
|
||||
|
|
|
@ -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.
|
||||
|
||||
[[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 to formulas
|
||||
|
||||
|
|
Loading…
Reference in New Issue