HHH-11186 - Add examples for all Hibernate annotations

Document @OnDelete annotation
This commit is contained in:
Vlad Mihalcea 2017-05-25 17:12:39 +03:00
parent a7f77e2687
commit baf194d422
5 changed files with 190 additions and 1 deletions

View File

@ -1047,7 +1047,7 @@ The two possible strategies are defined by the https://docs.jboss.org/hibernate/
CASCADE:: Use the database FOREIGN KEY cascade capabilities. CASCADE:: Use the database FOREIGN KEY cascade capabilities.
NO_ACTION:: Take no action. NO_ACTION:: Take no action.
//TODO: Add example See the <<chapters/pc/PersistenceContext.adoc#pc-cascade-on-delete, `@OnDelete` cascade>> chapter for more info.
[[annotations-hibernate-optimisticlock]] [[annotations-hibernate-optimisticlock]]
==== `@OptimisticLock` ==== `@OptimisticLock`

View File

@ -696,6 +696,7 @@ Even if just the `Person` parent entity was persisted, Hibernate has managed to
The `CascadeType.MERGE` allows us to merge a child entity along with the parent one. The `CascadeType.MERGE` allows us to merge a child entity along with the parent one.
[[pc-cascade-merge-example]]
.`CascadeType.MERGE` example .`CascadeType.MERGE` example
==== ====
[source, JAVA, indent=0] [source, JAVA, indent=0]
@ -755,6 +756,7 @@ Such a use case requires the use of the `PessimisticLockScope.EXTENDED` value of
However, `CascadeType.LOCK` allows us to reattach a parent entity along with its children to the currently running Persistence Context. However, `CascadeType.LOCK` allows us to reattach a parent entity along with its children to the currently running Persistence Context.
[[pc-cascade-lock-example]]
.`CascadeType.LOCK` example .`CascadeType.LOCK` example
==== ====
[source, JAVA, indent=0] [source, JAVA, indent=0]
@ -769,6 +771,7 @@ include::{sourcedir}/CascadeLockTest.java[tags=pc-cascade-lock-example]
The `CascadeType.REFRESH` is used to propagate the refresh operation from a parent entity to a child. The `CascadeType.REFRESH` is used to propagate the refresh operation from a parent entity to a child.
The refresh operation will discard the current entity state, and it will override it using the one loaded from the database. The refresh operation will discard the current entity state, and it will override it using the one loaded from the database.
[[pc-cascade-refresh-example]]
.`CascadeType.REFRESH` example .`CascadeType.REFRESH` example
==== ====
[source, JAVA, indent=0] [source, JAVA, indent=0]
@ -790,6 +793,7 @@ In the aforementioned example, you can see that both the `Person` and `Phone` en
The `CascadeType.REPLICATE` is to replicate both the parent and the child entities. The `CascadeType.REPLICATE` is to replicate both the parent and the child entities.
The replicate operation allows you to synchronize entities coming from different sources of data. The replicate operation allows you to synchronize entities coming from different sources of data.
[[pc-cascade-replicate-example]]
.`CascadeType.REPLICATE` example .`CascadeType.REPLICATE` example
==== ====
[source, JAVA, indent=0] [source, JAVA, indent=0]
@ -805,3 +809,42 @@ include::{extrasdir}/pc-cascade-replicate-example.sql[]
As illustrated by the SQL statements being generated, both the `Person` and `Phone` entities are replicated to the underlying database rows. As illustrated by the SQL statements being generated, both the `Person` and `Phone` entities are replicated to the underlying database rows.
[[pc-cascade-on-delete]]
==== `@OnDelete` cascade
While the previous cascade types propagate entity state transitions, the `@OnDelete` cascade is a DDL-level FK feature which allows you
to remove a child record whenever the parent row is deleted.
So, when annotating the `@ManyToOne` association with `@OnDelete( action = OnDeleteAction.CASCADE )`,
the automatic schema generator will apply the ON DELETE CASCADE SQL directive to the Foreign Key declaration,
as illustrated by the following example.
[[pc-cascade-on-delete-mapping-example]]
.`@OnDelete` mapping
====
[source, JAVA, indent=0]
----
include::{sourcedir}/CascadeOnDeleteTest.java[tags=pc-cascade-on-delete-mapping-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-cascade-on-delete-mapping-example.sql[]
----
====
Now, you can just remove the `Person` entity, and the associated `Phone` is going to be removed automatically.
[[pc-cascade-on-delete-example]]
.`@OnDelete` example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/CascadeOnDeleteTest.java[tags=pc-cascade-on-delete-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-cascade-on-delete-example.sql[]
----
====

View File

@ -0,0 +1,3 @@
delete from Person where id = ?
-- binding parameter [1] as [BIGINT] - [1]

View File

@ -0,0 +1,18 @@
create table Person (
id bigint not null,
name varchar(255),
primary key (id)
)
create table Phone (
id bigint not null,
"number" varchar(255),
owner_id bigint,
primary key (id)
)
alter table Phone
add constraint FK82m836qc1ss2niru7eogfndhl
foreign key (owner_id)
references Person
on delete cascade

View File

@ -0,0 +1,125 @@
package org.hibernate.userguide.pc;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
/**
* @author Vlad Mihalcea
*/
public class CascadeOnDeleteTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class,
Phone.class
};
}
@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
Person person = new Person();
person.setId( 1L );
person.setName( "John Doe" );
entityManager.persist( person );
Phone phone = new Phone();
phone.setId( 1L );
phone.setNumber( "123-456-7890" );
phone.setOwner( person );
entityManager.persist( phone );
} );
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::pc-cascade-on-delete-example[]
Person person = entityManager.find( Person.class, 1L );
entityManager.remove( person );
//end::pc-cascade-on-delete-example[]
} );
}
//tag::pc-cascade-on-delete-mapping-example[]
@Entity(name = "Person")
public static class Person {
@Id
private Long id;
private String name;
//Getters and setters are omitted for brevity
//end::pc-cascade-on-delete-mapping-example[]
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//tag::pc-cascade-on-delete-mapping-example[]
}
@Entity(name = "Phone")
public static class Phone {
@Id
private Long id;
@Column(name = "`number`")
private String number;
@ManyToOne(fetch = FetchType.LAZY)
@OnDelete( action = OnDeleteAction.CASCADE )
private Person owner;
//Getters and setters are omitted for brevity
//end::pc-cascade-on-delete-mapping-example[]
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
//tag::pc-cascade-on-delete-mapping-example[]
}
//end::pc-cascade-on-delete-mapping-example[]
}