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: *