Quick Contact

    Hibernate

    JPA and Hibernate Cascade Types

    JPA allows you to propagate the state transition from a parent entity to a child. For this purpose, the JPA javax.persistence.CascadeType defines various cascade types:

    • ALL – cascades all entity state transitions
    • PERSIST – cascades the entity persist operation.
    • MERGE – cascades the entity merge operation.
    • REMOVE – cascades the entity remove operation.
    • REFRESH – cascades the entity refresh operation.
    • DETACH – cascades the entity detach operation.

    Additionally, the CascadeType.ALL will propagate any Hibernate-specific operation, which is defined by the org.hibernate.annotations.CascadeType enum:

    • SAVE_UPDATE – cascades the entity saveOrUpdate operation.
    • REPLICATE – cascades the entity replicate operation.
    • LOCK – cascades the entity lock operation.

    Cascading only makes sense only for Parent-Child associations (the Parent entity state transition being cascaded to its Child entities). Cascading from Child to Parent is not very useful and usually, it’s a mapping code smell.

    The following examples will explain some of the aforementioned cascade operations using the following entities:

    @Entity
    publicclassPerson {
    
    @Id
    privateLong id;
    
    privateString name;
    
    @OneToMany(mappedBy="owner", cascade=CascadeType.ALL)
    privateList< Phone> phones =newArrayList<> ();
    
    //Getters and setters are omitted for brevity
    
    publicvoidaddPhone(Phonephone) {
    this.phones.add(phone);
    phone.setOwner(this);
        }
    }
    
    
    @Entity
    publicclassPhone {
    
    @Id
    privateLong id;
    
    @Column(name="`number`")
    privateString number;
    
    @ManyToOne(fetch=FetchType.LAZY)
    privatePerson owner;
    
    //Getters and setters are omitted for brevity
    }
    

    CascadeType.PERSIST

    The CascadeType.PERSIST allows us to persist a child entity along with the parent one.

    CascadeType.PERSIST example

    Personperson=newPerson();
    person.setId(1L );
    person.setName("John Doe" );
    
    Phonephone=newPhone();
    phone.setId(1L );
    phone.setNumber("123-456-7890" );
    
    person.addPhone( phone );
    
    entityManager.persist( person );
    

    The above hibernate code prints following SQL statements at the console:

    INSERTINTOPerson( name, id )
    VALUES( 'John Doe', 1 )
    
    INSERTINTOPhone( `number`, person_id, id )
    VALUE( '123-456-7890', 1, 1 )
    

    From above SQL statements proves that when Person persist into a database it also persists it’s child Phone object.

    CascadeType.MERGE

    The CascadeType.MERGE allows us to merge a child entity along with the parent one.

    CascadeType.MERGE example

    Phonephone=entityManager.find(Phone.class, 1L );
    Personperson=phone.getOwner();
    
    person.setName("John Doe Jr." );
    phone.setNumber("987-654-3210" );
    
    entityManager.clear();
    
    entityManager.merge( person );
    

    The above hibernate code prints following SQL statements at the console:

    SELECT
    p.idas id1_0_1_,
    p.nameas name2_0_1_,
    ph.owner_idas owner_id3_1_3_,
    ph.idas id1_1_3_,
    ph.idas id1_1_0_,
    ph."number"as number2_1_0_,
    ph.owner_idas owner_id3_1_0_
    FROM
        Person p
    LEFT OUTER JOIN
        Phone ph
    onp.id=ph.owner_id
    WHERE
    p.id=1
    

    During a merge, the current state of the entity is copied onto the entity version that was just fetched from the database. That’s the reason why Hibernate executed the SELECT statement which fetched both the Person entity along with its children.

    CascadeType.REMOVE

    The CascadeType.REMOVE allows us to remove a child entity along with the parent one. Traditionally, Hibernate called this operation delete, that’s why the org.hibernate.annotations.CascadeType provides a DELETE cascade option. However, CascadeType.REMOVE and org.hibernate.annotations.CascadeType.DELETE are identical.

    CascadeType.REMOVE example

    Personperson=entityManager.find(Person.class, 1L );

    entityManager.remove( person );

    The above hibernate code prints following SQL statements at the console:

    DELETEFROM Phone WHERE id =1

    DELETEFROM Person WHERE id =1

    CascadeType.DETACH

    CascadeType.DETACH is used to propagate the detach operation from a parent entity to a child.

    CascadeType.DETACH example

    Personperson=entityManager.find(Person.class, 1L );
    assertEquals(1, person.getPhones().size() );
    Phonephone=person.getPhones().get( 0 );
    
    assertTrue(entityManager.contains( person ));
    assertTrue(entityManager.contains( phone ));
    
    entityManager.detach( person );
    
    assertFalse(entityManager.contains( person ));
    assertFalse(entityManager.contains( phone ));
    

    CascadeType.LOCK

    Although unintuitively, CascadeType.LOCK does not propagate a lock request from a parent entity to its children. Such a use case requires the use of

    the PessimisticLockScope.EXTENDED value of the javax.persistence.lock.scope property.

    However, CascadeType.LOCK allows us to reattach a parent entity along with its children to the currently running Persistence Context.

    CascadeType.LOCK example

    Personperson=entityManager.find(Person.class, 1L );
    assertEquals(1, person.getPhones().size() );
    Phonephone=person.getPhones().get( 0 );
    
    assertTrue(entityManager.contains( person ) );
    assertTrue(entityManager.contains( phone ) );
    
    entityManager.detach( person );
    
    assertFalse(entityManager.contains( person ) );
    assertFalse(entityManager.contains( phone ) );
    
    entityManager.unwrap(Session.class )
      .buildLockRequest(newLockOptions( LockMode.NONE ) )
      .lock( person );
    
    assertTrue(entityManager.contains( person ) );
    assertTrue(entityManager.contains( phone ) );
    

    CascadeType.REFRESH

    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.

    CascadeType.REFRESH example

    Personperson=entityManager.find(Person.class, 1L );
    Phonephone=person.getPhones().get( 0 );
    
    person.setName("John Doe Jr." );
    phone.setNumber("987-654-3210" );
    
    entityManager.refresh( person );
    
    assertEquals("John Doe", person.getName() );
    assertEquals("123-456-7890", phone.getNumber() );
    

    The above hibernate code prints following SQL statements at the console:

    SELECT
    p.idas id1_0_1_,
    p.nameas name2_0_1_,
    ph.owner_idas owner_id3_1_3_,
    ph.idas id1_1_3_,
    ph.idas id1_1_0_,
    ph."number"as number2_1_0_,
    ph.owner_idas owner_id3_1_0_
    FROM
        Person p
    LEFT OUTER JOIN
        Phone ph
    ONp.id=ph.owner_id
    WHERE
    p.id=1
    

    In the aforementioned example, you can see that both the Person and Phone entities are refreshed even if we only called this operation on the parent entity only.

    CascadeType.REPLICATE

    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.

    CascadeType.REPLICATE example

    Personperson=newPerson();
    person.setId(1L );
    person.setName("John Doe Sr." );
    
    Phonephone=newPhone();
    phone.setId(1L );
    phone.setNumber("(01) 123-456-7890" );
    person.addPhone( phone );
    
    entityManager.unwrap(Session.class ).replicate( person, ReplicationMode.OVERWRITE );
    

    The above hibernate code prints following SQL statements at the console:

    SELECT
    id
    FROM
        Person
    WHERE
    id=1
    
    SELECT
    id
    FROM
        Phone
    WHERE
    id=1
    
    UPDATE
        Person
    SET
    name='John Doe Sr.'
    WHERE
    id=1
    
    UPDATE
        Phone
    SET
    "number"='(01) 123-456-7890',
    owner_id=1
    WHERE
    id=1
    

    Apply now for Advanced Java Training Course

    Copyright 1999- Ducat Creative, All rights reserved.

    Anda bisa mendapatkan server slot online resmi dan terpercaya tentu saja di sini. Sebagai salah satu provider yang menyediakan banyak pilihan permainan.