How to check two entities are equal in JPA

Consider we have a use case where we want to compare two entities values. For example one entity we supplying from UI and another one we are retrieving from the database for the same id. We want to check both entities i.e one is from UI and the other is from DB are the same or not. To check if two entities are equal in JPA, we need to override the equals() and hashCode() methods in our entity class. The implementation should compare the unique identifier of each entity, which is usually mapped to the primary key in the database i.e in most cases id.

Here’s an example of how to override these methods.

import javax.persistence.*;
import java.util.Objects;

@Entity
public class Student {
 
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "id")
  private Long id;
 
  @Column(name = "name")
  private String name;
 
  @Column(name = "roll_number")
  private String rollNumber;
 
  @Column(name = "university")
  private String university;
 
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return Objects.equals(id, student.id);
  }
 
  @Override
  public int hashCode() {
    return Objects.hash(id);
  }
 
  // getters and setters
}

In this example, the hashCode() method returns the hash code of the id field, and the equals()method compares the id fields of two Student instances to determine their equality. By using these methods to check equality, we can ensure that two Student instances are considered equal only if their id fields are equal.

This can be useful in various scenarios where we need to determine if two Student instances are the same, for example, when adding or removing elements from a collection. Also, as we discussed at the beginning we can check two entities(i.e one from UI and another from DB) are equal or not.

By using this implementation, we can use the equals() method to compare two entities and determine if they represent the same record in the database.

    @Transactional
    public Student checkEqualityOfEntities(Student student) {

        //Check student supplied from UI is equal to existing student i.e DB
        Optional<Student> existingStudentResponse = studentRepository.findById(student.getId());
        Student existingStudent = existingStudentResponse.get();

        if (existingStudent != null && existingStudent.equals(student)) {
            return existingStudent;
        } else {
            return null;
        }
    }

Let’s see what’s going on inside checkEqualityOfEntities() method. This method checks the equality of two Student entities. The method takes a Student object as input, which represents the student entity supplied by the user interface. The first step in the method is to retrieve an existing student from the database using the studentRepository.findById() method and the id of the input student object.

The findById() method returns an Optional object, which is used to retrieve the existing student from the database if it exists. Next, the code checks if the existing student is not null and if it is equal to the input student using the equals method. If both conditions are true, the existing student is returned. If either condition is false, the method returns null.

The purpose of this method is to determine if the input Student entity is equal to an existing Student entity in the database. The equality check is performed by using the equals() method that was overridden in the Student entity, which compares the id field of two Student instances to determine their equality.

How to Compare all JPA entity field value

We might want to compare each field value one by one, we can use reflection for this.

    @Transactional
    public Student update(Student student) {

        Optional<Student> response = studentRepository.findById(student.getId());
        Student fromDb = response.get();
        boolean valueChanged = false;
        if (fromDb != null) {

            // Use reflection to get and compare the values of all fields
            Field[] fields = Student.class.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                try {
                    Object existingValue = field.get(fromDb);
                    Object entityNeedsToUpdate = field.get(student);

                    if (!Objects.equals(existingValue, entityNeedsToUpdate)) {
                        field.set(fromDb, entityNeedsToUpdate);
                        valueChanged = true;

                    }
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
            if (valueChanged) {
                return studentRepository.save(fromDb);
            } else {
                return student;
            }
        }
        return student;
    }

In this updated example, we use Java reflection to iterate through all the fields of the entity class, set them as accessible, and then compare the existing values with the updated values. If a difference is detected, the field is updated. This approach allows you to handle entities with a large number of fields more efficiently without manually coding each field update.

However, please be aware that using reflection can have performance implications and should be used with caution. It’s essential to thoroughly test and validate this approach in your specific use case to ensure it meets your performance and security requirements.

Let’s see the complete example of How to check two entities are equal in JPA.

Create a maven project and add the dependency.

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>howto</groupId>
    <artifactId>howtochecktwoentitiesareequalinjpa</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

</project>

Project structure

How to check two entities are equal in JPA
Project structure for How to check two entities are equal in JPA

Define configuration file

package com.javatute.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@EnableJpaRepositories(basePackages = "com.javatute.repository")
public class JpaConfig {
}

Define entity class

package com.javatute.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Student implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "name")
    private String name;

    @Column(name = "roll_number")
    private String rollNumber;

    @Column(name = "university")
    private String university;
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id);
     }
 
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    //getter & setter
}

Define StudentRepository interface

package com.javatute.repository;

import com.javatute.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.io.Serializable;
import java.util.List;

@Repository
public interface StudentRepository extends JpaRepository<Student, Serializable> {

}

Define StudentService.java

package com.javatute.service;

import com.javatute.entity.Student;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public interface StudentService {
    public Student checkEqualityOfEntities(Student student);
}

Define ServiceImpljava

Define StudentServiceImpl.java

package com.javatute.serviceimpl;

import com.javatute.config.RestClient;
import com.javatute.entity.Student;
import com.javatute.repository.StudentRepository;
import com.javatute.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

@Service
public class StudentServiceImpl implements StudentService {

    @Autowired
    private StudentRepository studentRepository;

    @Transactional
    public Student checkEqualityOfEntities(Student student) {

        //Check student supplied from UI is equal to existing student.
        Optional<Student> existingStudentResponse = studentRepository.findById(student.getId());
        Student existingStudent = existingStudentResponse.get();

        if (existingStudent != null && existingStudent.equals(student)) {
            return existingStudent;
        } else {
            return null;
        }
    }
}

StudentController.java

package com.javatute.controller;

import com.javatute.entity.Student;
import com.javatute.repository.StudentRepository;
import com.javatute.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private StudentService studentService;


    @PostMapping("/create")
    public Student createStudent1(@RequestBody Student student) {
        Student createResponse = studentService.save(student);
        return createResponse;
    }

}

services.properties

spring.datasource.url=jdbc:mysql://localhost:3306/springbootcrudexample
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
server.port = 9091

SprinMain.java

package com.javatute.main;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.javatute.*")
@EntityScan("com.javatute.*")
public class SpringMain {
    public static void main(String[] args) {
        SpringApplication.run(SpringMain.class, args);
    }
}

Run and test the example.

http://localhost:9091/student/checkequalityofentities

That’s all about How to check two entities are equal in JPA.

Related post.

See docs