Defining object equality by primary key

Consider the following code:

package session1;
	  ...
	  public class LoadUser {
	  ...
	  final User user;
	  {
          final Session session = HibernateUtil.createSessionFactory("session1/hibernate.cfg.xml").openSession();
          final Transaction transaction = session.beginTransaction();
          user = (User) session.load(User.class, 1L);
          final User user1 = (User) session.load(User.class, 1L);

          System.out.println("first transaction: user.equals(user1):" + user.equals(user1)); ❶

          transaction.commit();
          session.close();
	  }
	  {
          final Session session = HibernateUtil.createSessionFactory("session1/hibernate.cfg.xml").openSession();
          final Transaction transaction = session.beginTransaction();
          final User user2 = (User) session.load(User.class, 1L);

          System.out.println("second transaction: user.equals(user2):" + user.equals(user2)); ❷

          transaction.commit();
          session.close();
	  } ...

At first we compare two session1.User instances being read by the same session manager ❶. Subsequently we compare a detached session1.User instance with a second instance being read by a different session ❷. This yields the following result:

first transaction: user.equals(user1):true ❶
second transaction: user.equals(user2):false 

The two instances in question definitely represent the same database entity. The two entity managers referring to different sessions create two distinct instances within a given Java runtime.

Since JPA entities require an @javax.persistence.Id attribute we may generally define object equality solely based on this at tribute's value:

package session2;
	  ...
	  public class User {

	  @Id @GeneratedValue
	  private Long id;
	  ...
	  @Override public boolean equals(Object other) {
	  if (this == other) {
	  return true;
	  } else if (other instanceof User) {
	  return getId().equals(((User) other).getId()) ;
	  } else {
	  return false;
	  }
	  }
	  @Override public int hashCode() { 
	  if (null == id) {
	  return System.identityHashCode(this);
	  } else {
	  return getId().hashCode();
	  }
	  }
	  }

This way of defining session2.User.equals(java.lang.Object) implies that either or both of the following two conditions must be met:

Both instances must be identical.

Both instances must have the same session2.User.getId() value. It is not necessary to prepend null != other && other instanceof User since the operator instanceof evaluates to false if its left side is null.

Caution

Do not forget to implement Object.hashCode() accordingly: Two instances a and b returning a.equals(b) == true equal must return an identical hash code value a.hashCode() == b.hashCode() in order to satisfy a collection's contract.

[Bloch2008] covers the contract of Object.hashCode() and its close relation to Object.equals(Object) in detail.