diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc index ed0d000e62..c66e16b473 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/QueryLanguage.adoc @@ -232,9 +232,22 @@ include::{example-dir-hql}/../batch/BatchTests.java[tags=batch-bulk-hql-update-v Update statements are polymorphic, and affect mapped subclasses of the given entity class. -[IMPORTANT] +An `update` statement may use implicit or explicit joins. Beware that if joins lead to row duplications, +e.g. when joining the target row against a non-unique column, +it is undefined which row is updated or whether an error is thrown. + +[[hql-update-join-example]] +//.Example update join queries ==== -No `update` or `delete` statement may have an implicit (or explicit) join. +[source, JAVA, indent=0] +---- +include::{example-dir-hql}/../query/hql/UpdateJoinTests.java[tags=hql-update-join-example] +---- +==== + +[NOTE] +==== +With JPA compliance enabled, `update` or `delete` statement may not have an implicit (or explicit) join. ==== [[hql-delete]] @@ -257,6 +270,22 @@ The integer value returned by `executeUpdate()` indicates the number of entity i Delete statements are polymorphic, and affect mapped subclasses of the given entity class. +A `delete` statement may use implicit or explicit joins. + +[[hql-delete-join-example]] +//.Example delete join queries +==== +[source, JAVA, indent=0] +---- +include::{example-dir-hql}/../query/hql/DeleteJoinTests.java[tags=hql-delete-join-example] +---- +==== + +[NOTE] +==== +With JPA compliance enabled, `update` or `delete` statement may not have an implicit (or explicit) join. +==== + [[hql-insert]] ==== Insert statements diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_delete_bnf.txt b/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_delete_bnf.txt index 89d11a67b0..7cf464c65b 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_delete_bnf.txt +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_delete_bnf.txt @@ -1,2 +1,8 @@ deleteStatement - : "DELETE" "FROM"? targetEntity whereClause? + : "DELETE" "FROM"? entityWithJoins whereClause? + +entityWithJoins + : fromRoot (join | crossJoin | jpaCollectionJoin)* + +fromRoot + : entityName variable? diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_update_bnf.txt b/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_update_bnf.txt index 065bf85364..70548fa5b2 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_update_bnf.txt +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/extras/statement_update_bnf.txt @@ -1,5 +1,11 @@ updateStatement - : "UPDATE" "VERSIONED"? targetEntity setClause whereClause? + : "UPDATE" "VERSIONED"? entityWithJoins setClause whereClause? + +entityWithJoins + : fromRoot (join | crossJoin | jpaCollectionJoin)* + +fromRoot + : entityName variable? targetEntity : entityName variable? diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DeleteJoinTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DeleteJoinTests.java index 63a94cdf5a..565e5b5292 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DeleteJoinTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/DeleteJoinTests.java @@ -63,10 +63,12 @@ public class DeleteJoinTests { public void testDeleteWithJoin(SessionFactoryScope scope) { scope.inTransaction( session -> { + //tag::hql-delete-join-example[] int updated = session.createMutationQuery( "delete from BasicEntity b left join Contact c on b.id = c.id " + "where c.id is not null" ).executeUpdate(); + //end::hql-delete-join-example[] assertEquals( 1, updated ); assertNull( session.find( BasicEntity.class, 1 ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/UpdateJoinTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/UpdateJoinTests.java index a8e9ca6360..66a34792de 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/UpdateJoinTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/UpdateJoinTests.java @@ -62,11 +62,13 @@ public class UpdateJoinTests { public void testUpdateWithJoin(SessionFactoryScope scope) { scope.inTransaction( session -> { + //tag::hql-update-join-example[] int updated = session.createMutationQuery( "update BasicEntity b left join Contact c on b.id = c.id " + "set b.data = c.name.first " + "where c.id is not null" ).executeUpdate(); + //end::hql-update-join-example[] assertEquals( 1, updated ); final BasicEntity basicEntity = session.find( BasicEntity.class, 1 ); assertEquals( "A", basicEntity.getData() );