Entities in real-world applications often have associations with other entities. These associations can be simple or complex, sometimes leading to deeply nested objects. Spring Data JPA makes querying these relationships a breeze using method conventions. In this blog post, we'll explore how to use the findBy method to query nested objects.
JPA Entities - Employee and Address
In this example, let's assume we're building an HR system. We have two primary entities: Employee and Address.
Employee
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
}
Address
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Entity
@Table(name = "addresses")
public class Address1 {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String city;
private String country;
}
Notice the @OneToOne annotation, indicating a one-to-one relationship between Employee and Address.
@Getter: Generates getter methods for the fields of the class.
Spring Data JPA Repository - EmployeeRepository
Let's create an EmployeeRepository interface that extends the JpaRepository interface from Spring Data JPA:
import com.springdatajpa.springboot.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
Querying Nested Objects
Let's say we want to fetch all employees based on their city. How do we achieve that? With Spring Data JPA, it's astonishingly simple:
import com.springdatajpa.springboot.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
List<Employee> findByAddress_City(String city);
}
Notice the findByAddress_City method. The underscore (_) is a special character in Spring Data JPA and allows us to traverse the entity graph and bind the property to the nested property.
Under the Hood
When you call findByAddress_City, Spring Data JPA will generate a SQL query similar to:
select
e1_0.id,
e1_0.address_id,
e1_0.name
from
employees e1_0
left join
addresses a1_0
on a1_0.id=e1_0.address_id
where
a1_0.city=?
Testing - EmployeeRepository Query Methods
Let's write the JUnit test cases to all the above query methods:
@Test
void findByFirstNameAndLastNameTest(){
List<Employee> employees = employeeNestedRepository.findByAddress_City("Pune");
employees.forEach((employee) -> {
System.out.println(employee.toString());
});
}
Output:
Hibernate:
select
e1_0.id,
e1_0.address_id,
e1_0.name
from
employees e1_0
left join
addresses a1_0
on a1_0.id=e1_0.address_id
where
a1_0.city=?
Conclusion
Spring Data JPA continues to shine when it comes to simplifying database interactions in Java applications. Its conventions around method naming, especially with nested objects, means that developers can quickly write queries without having to dive deep into SQL or JPQL. However, it's essential to be aware of the trade-offs and to know when to use these conventions vs. when to write custom queries. Happy coding!
Comments
Post a Comment
Leave Comment