Spring Data JPA: Entity Lifecycle Model

  • Post last modified:June 6, 2023
  • Reading time:4 mins read

Discussing JPA Entity states with examples

Introduction

  • JPA provides the persistent context within which entity instance and their lifecycle is managed.
  • In this article, we will discuss these states with examples.

Entity Lifecycle Model

  • The entity lifecycle model consists of the following 4 states.

Transient

  • When we instantiated a new entity its state is transient. It’s nothing more than basic Java Objects which doesn’t have any connection to the database.
  • It doesn’t represent database records and doesn’t perform any database query.
  • But that changes when we call persist method or load/find the entity from the database.
 public Account getAccount() {
        Permission permission = getPermission();
        // account is in transient state
        Account account = new Account();
        String seed = UUID.randomUUID().toString();
        account.setUsername("sam_1234");
        account.setEmail("username_"+seed+"@gmail.com");
        account.setPermission(permission);
        account.setPassword("password_q1234");
        account.setCreatedOn(Timestamp.from(Instant.now()));
        account.setLastLogin(Timestamp.from(Instant.now()));
        return account;
}

Managed

  • All the entities that got attached persistence context are in the managed state. Since it’s managed by persistence context, any changes to an entity will be tracked and equivalent queries will be issued to the underlying database.
  • In order to get an entity in the managed state, you can call persist method, query the database, and load the entity or merge/update the entity by calling the merge method.
  public void persist(){
        Account account = getAccount();
        em.persist(account); // account is now managed by persistence context.
        System.out.println("contains account: "+em.contains(account)); // true
   }
   
   public Account getAccount() {
        Permission permission = getPermission();
        Account account = new Account();
        String seed = UUID.randomUUID().toString();
        account.setUsername("sam_1234");
        account.setEmail("username_"+seed+"@gmail.com");
        account.setPermission(permission);
        account.setPassword("password_q1234");
        account.setCreatedOn(Timestamp.from(Instant.now()));
        account.setLastLogin(Timestamp.from(Instant.now()));
        return account;
    }

Output

Removed

  • When we call the remove method on the entity, the entity state changes to remove.
  • Although the entity is not immediately deleted from the database. That only happens during the next flush operation.
em.remove(account);
  • Here we are finding the entity from the database and printing if the entity manager contains it.
  • After that, we are removing it from the persistence context hence the output of contains will be false.
Account account = accountRepository.findByUsername("sam_1234").get();
System.out.println("account contains: "+ em.contains(account));
em.remove(account);
System.out.println("account contains: "+ em.contains(account));

Output

Detached

  • The entity which was previously managed but is no longer attached to the current persistence context is in the lifecycle stage detached.
  • When we commit the transaction, the persistence context gets closed and the entity gets detached. After the entity gets detached any changes don’t get propagated to the database.
  • If we want to detach an entity programmatically, we can also programmatically call detach method.
em.detach(account);
  • We find the entity which is managed by persistence context, we can verify using contains method as shown below.
  • We detach the entity using detach method, the entity is no longer managed by persistence context.
Account account = accountRepository.findByUsername("username_12345").get();
System.out.println("account contains: "+ em.contains(account)); // true 
em.detach(account);
System.out.println("account contains: "+ em.contains(account)); // false

Output

  • We can call merge on the entity to attach it back to the persistence context.
Account updatedAccount = em.merge(account);
//updatedAccount is managed by persistence context and account is not.
  • Once we detached the account entity, we can merge it, and the returned instance will become a managed entity. If we call contains on it we will return true.
Account account = accountRepository.findByUsername("username_12345").get();
System.out.println("account contains: "+ em.contains(account)); // true

em.detach(account); // detach entity
System.out.println("account contains: "+ em.contains(account)); // false

account.setPassword("vdssfevrgmrsnfsrfvrhgf");
Account mergedAccount = em.merge(account);
System.out.println("account contains: "+ em.contains(mergedAccount)); // true

Output

Conclusion

  • In this article, we discuss 4 states of the JPA entity and the transition from one to another.
  • We also discussed each state with code examples.

Before You Leave

Leave a Reply