From 491c02f935214b4096022ea8e28bd5aabf4fff04 Mon Sep 17 00:00:00 2001 From: Gavin Date: Wed, 17 May 2023 17:08:22 +0200 Subject: [PATCH] some more tips --- .../main/asciidoc/introduction/Advanced.adoc | 27 ++++++++++++++----- .../main/asciidoc/introduction/Mapping.adoc | 14 +++++++--- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/documentation/src/main/asciidoc/introduction/Advanced.adoc b/documentation/src/main/asciidoc/introduction/Advanced.adoc index 3e7d349096..d6b85436c1 100644 --- a/documentation/src/main/asciidoc/introduction/Advanced.adoc +++ b/documentation/src/main/asciidoc/introduction/Advanced.adoc @@ -89,13 +89,18 @@ For this we can use `@SQLInsert` and friends: [source,java] ---- @Entity -@SQLInsert(sql = "INSERT INTO person (name, id, valid) VALUES (?, ?, true) ", check = COUNT) -@SQLUpdate(sql = "UPDATE person SET name = ? where id = ? ") -@SQLDelete(sql = "UPDATE person SET valid = false WHERE id = ? ") -@SQLSelect(sql = "SELECT id, name FROM person WHERE id = ? and valid = true") +@SQLInsert(sql = "insert into person (name, id, valid) values (?, ?, true)", check = COUNT) +@SQLUpdate(sql = "update person set name = ? where id = ?") +@SQLDelete(sql = "update person set valid = false where id = ?") +@SQLSelect(sql = "select id, name from person where id = ? and valid = true") public static class Person { ... } ---- +[TIP] +==== +If the custom SQL should be executed via a `CallableStatement`, just specify `callable=true`. +==== + Any SQL statement specified by one of these annotations must have exactly the number of JDBC parameters that Hibernate expects, that is, one for each column mapped by the entity, in the exact order Hibernate expects. In particular, the primary key columns must come last. However, the `@Column` annotation does lend some flexibility here: @@ -103,9 +108,17 @@ However, the `@Column` annotation does lend some flexibility here: - if a column should not be written as part of the custom `insert` statement, and has no corresponding JDBC parameter in the custom SQL, map it `@Column(insertable=false)`, or - if a column should not be written as part of the custom `update` statement, and has no corresponding JDBC parameter in the custom SQL, map it `@Column(updatable=false)`. -In either of these cases, it's possible that the custom `insert` or `update` statement assigns a value to the mapped column as it is written, for example, by calling a SQL function. -But our entity instance won't be automatically populated with that value. -We may use the `@Generated` annotation to tell Hibernate to reread the state of the entity after each `insert` and/or `update`. +Sometimes a custom `insert` or `update` statement assigns a value to a mapped column which is calculated when the statement is executed on the database. +For example, the value might be obtained by calling a SQL function: + +[source,java] +---- +@SQLInsert(sql = "insert into person (name, id) values (?, gen_random_uuid())") +---- + +But the entity instance which represents the row being inserted or updated won't be automatically populated with that value. +And so our persistence context loses synchronization with the database. +In situations like this, we may use the `@Generated` annotation to tell Hibernate to reread the state of the entity after each `insert` or `update`. [[database-generated-columns]] === Handling database-generated columns diff --git a/documentation/src/main/asciidoc/introduction/Mapping.adoc b/documentation/src/main/asciidoc/introduction/Mapping.adoc index d18d7b3a57..ac11df9d9f 100644 --- a/documentation/src/main/asciidoc/introduction/Mapping.adoc +++ b/documentation/src/main/asciidoc/introduction/Mapping.adoc @@ -352,8 +352,8 @@ The `@Column` annotation is not only useful for specifying the column name. | `scale` | The scale of a `DECIMAL` or `NUMERIC` column type, the digits of precision that occur to the right of the decimal point | `unique` | Whether the column has a `UNIQUE` constraint | `nullable` | Whether the column has a `NOT NULL` constraint -| `insertable` | Whether the column should appear in generated SQL `INSERT` and `UPDATE` statements -| `updatable` | Whether the column should appear in generated SQL `INSERT` and `UPDATE` statements +| `insertable` | Whether the column should appear in generated SQL `INSERT` statements +| `updatable` | Whether the column should appear in generated SQL `UPDATE` statements | `columnDefinition` 💀| A DDL fragment that should be used to declare the column |=== @@ -404,8 +404,8 @@ The `@JoinColumn` annotation is used to customize a foreign key column. | `referencedColumnName` | The name of the column to which the mapped foreign key column refers | `unique` | Whether the column has a `UNIQUE` constraint | `nullable` | Whether the column has a `NOT NULL` constraint -| `insertable` | Whether the column should appear in generated SQL `INSERT` and `UPDATE` statements -| `updatable` | Whether the column should appear in generated SQL `INSERT` and `UPDATE` statements +| `insertable` | Whether the column should appear in generated SQL `INSERT` statements +| `updatable` | Whether the column should appear in generated SQL `UPDATE` statements | `columnDefinition` 💀| A DDL fragment that should be used to declare the column | `foreignKey` | A `@ForeignKey` annotation specifying the name of the `FOREIGN KEY` constraint |=== @@ -617,6 +617,12 @@ Unfortunately, the driver for PostgreSQL doesn't allow `BYTEA` or `TEXT` columns This limitation of the Postgres driver has resulted in a whole cottage industry of bloggers and stackoverflow question-answerers recommending convoluted ways to hack the Hibernate `Dialect` for Postgres to allow an attribute annotated `@Lob` to be written using `setString()` and read using `getString()`. But simply removing the `@Lob` annotation has exactly the same effect. + +Conclusion: + +- on PostgreSQL, `@Lob` always means the `OID` type, +- `@Lob` should never be used to map columns of type `BYTEA` or `TEXT`, and +- please don't believe everything you read on stackoverflow. ==== Finally, as an alternative, Hibernate lets you declare an attribute of type `java.sql.Blob` or `java.sql.Clob`.