HHH-11186 - Add examples for all Hibernate annotations
Document @OnDelete annotation
This commit is contained in:
parent
a7f77e2687
commit
baf194d422
|
@ -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`
|
||||||
|
|
|
@ -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[]
|
||||||
|
----
|
||||||
|
====
|
|
@ -0,0 +1,3 @@
|
||||||
|
delete from Person where id = ?
|
||||||
|
|
||||||
|
-- binding parameter [1] as [BIGINT] - [1]
|
|
@ -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
|
|
@ -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[]
|
||||||
|
}
|
Loading…
Reference in New Issue