From 145fb646cc01d89b9efa24a4ecc8647ebef4ce7b Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 20 Jan 2025 11:18:39 +0100 Subject: [PATCH] improve javadoc for @View, @Subselect, and @SQLSelect --- .../org/hibernate/annotations/SQLSelect.java | 16 ++++++++ .../org/hibernate/annotations/Subselect.java | 37 +++++++++++++++++-- .../hibernate/annotations/Synchronize.java | 5 ++- .../java/org/hibernate/annotations/View.java | 15 ++++++-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/SQLSelect.java b/hibernate-core/src/main/java/org/hibernate/annotations/SQLSelect.java index 6ed1d13b41f6..6bff0311f35f 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/SQLSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/SQLSelect.java @@ -34,6 +34,22 @@ *
  • the foreign key, in the case of a collection. * *

    + * If the {@linkplain #querySpaces tables which affect the query results} + * are specified, then changes to those tables will be flushed before + * execution of the query. + *

    + * For example: + *

    + * @SQLSelect(sql = """
    + *                  SELECT id, created, text
    + *                  FROM records
    + *                  WHERE id = ? and deleted is null
    + *                  """
    + *            querySpaces = "records")
    + * @Entity
    + * public class Record { ... }
    + * 
    + *

    * Optionally, an explicit {@linkplain #resultSetMapping result set mapping} * may be specified. It should have: *

      diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Subselect.java b/hibernate-core/src/main/java/org/hibernate/annotations/Subselect.java index 2f298c326afb..42387fd1d1d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Subselect.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Subselect.java @@ -11,12 +11,41 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; /** - * Maps an immutable and read-only entity to a given SQL {@code select} expression. + * Maps an {@linkplain Immutable immutable} and read-only entity to a given + * SQL {@code select} expression. *

      - * This is an alternative to defining a database view and mapping the entity to - * the view using the {@link jakarta.persistence.Table @Table} annotation. + * For example: + *

      + * @Immutable @Entity
      + * @Subselect("""
      + *            select type, sum(amount) as total, avg(amount) as average
      + *            from details
      + *            group by type
      + *            """)
      + * @Synchronize("details")
      + * public class Summary {
      + *     @Id String type;
      + *     Double total;
      + *     Double average;
      + * }
      + * 
      + *

      + * This is an alternative to defining a {@linkplain View view} and mapping + * the entity to the view using the {@link jakarta.persistence.Table @Table} + * annotation. + *

      + * It's possible to have an entity class which maps a table, and another + * entity which is defined by a {@code @Subselect} involving the same table. + * In this case, a stateful session is vulnerable to data aliasing effects, + * and it's the responsibility of client code to ensure that changes to the + * first entity are flushed to the database before reading the same data via + * the second entity. The {@link Synchronize @Synchronize} annotation can + * help alleviate this problem, but it's an incomplete solution. We therefore + * recommend the use of {@linkplain org.hibernate.StatelessSession stateless + * sessions} in this situation. * * @see Synchronize + * @see View * * @author Sharath Reddy */ @@ -24,7 +53,7 @@ @Retention(RUNTIME) public @interface Subselect { /** - * The query. + * The subquery, written in native SQL. */ String value(); } diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java b/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java index bfbf114687ff..d543bf02c715 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java @@ -25,7 +25,7 @@ * Ordinarily, Hibernate knows the tables containing the state of an * entity or collection. This annotation might be necessary if: *

        - *
      • an entity or collection maps a database view, + *
      • an entity or collection maps a database {@linkplain View view}, *
      • an entity or collection is persisted using handwritten SQL, * that is, using {@link SQLSelect @SQLSelect} and friends, or *
      • an entity is mapped using {@link Subselect @Subselect}. @@ -41,6 +41,9 @@ * @author Sharath Reddy * * @see org.hibernate.query.SynchronizeableQuery + * @see View + * @see Subselect + * @see SQLSelect */ @Target({TYPE, FIELD, METHOD}) @Retention(RUNTIME) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/View.java b/hibernate-core/src/main/java/org/hibernate/annotations/View.java index 2f6665c31d0a..ac88c12e4d10 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/View.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/View.java @@ -26,7 +26,11 @@ *
          * @Immutable @Entity
          * @Table(name="summary")
        - * @View(query="select type, sum(amount) as total, avg(amount) as average from details group by type")
        + * @View(query="""
        + *             select type, sum(amount) as total, avg(amount) as average
        + *             from details
        + *             group by type
        + *             """)
          * @Synchronize("details")
          * public class Summary {
          *     @Id String type;
        @@ -34,11 +38,12 @@
          *     Double average;
          * }
          * 
        - *

        * results in the following generated DDL: *

          * create view summary
        - * as select type, sum(amount) as total, avg(amount) as average from details group by type
        + * as select type, sum(amount) as total, avg(amount) as average
        + *    from details
        + *    group by type
          * 
        *

        * If a view is not updatable, we recommend annotating the @@ -47,7 +52,7 @@ * It's possible to have an entity class which maps a table, * and another entity which maps a view defined as a query * against that table. In this case, a stateful session is - * vulnerable to data aliasing effects, and it is the + * vulnerable to data aliasing effects, and it's the * responsibility of client code to ensure that changes to * the first entity are flushed to the database before * reading the same data via the second entity. The @@ -61,6 +66,8 @@ * @since 6.3 * * @author Gavin King + * + * @see Synchronize */ @Incubating @Target(TYPE)