[ BAEL-5987 ] - Difference Between JPA and Spring Data JPA (#13209)

* feat: add jpa - spring data difference examples

* fix: remove _ from package name
This commit is contained in:
lucaCambi77 2023-01-05 04:34:13 +01:00 committed by GitHub
parent f28c9a79b8
commit f63772f5e4
9 changed files with 621 additions and 2 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
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>
<artifactId>spring-data-jpa-repo-2</artifactId>
<name>spring-data-jpa-repo-2</name>
@ -34,6 +34,14 @@
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
@ -41,4 +49,53 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>3.3.3</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>5.6.11.Final</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,76 @@
package com.baeldung.spring.data.persistence.springdatajpadifference.model;
import java.io.Serializable;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
@Entity
@Table(name = "employee")
@NamedQuery(name = "Employee.findById", query = "SELECT e FROM Employee e WHERE e.id = :id")
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String firstName;
@Column(nullable = false)
private String lastName;
@Column(nullable = false)
private String email;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Employee employee = (Employee) o;
return Objects.equals(id, employee.id) && Objects.equals(firstName, employee.firstName) && Objects.equals(lastName, employee.lastName) && Objects.equals(email, employee.email);
}
@Override
public int hashCode() {
return Objects.hash(id, firstName, lastName, email);
}
}

View File

@ -0,0 +1,66 @@
package com.baeldung.spring.data.persistence.springdatajpadifference.springdata.config;
import java.util.Properties;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository.EmployeeRepository;
import com.querydsl.jpa.impl.JPAQueryFactory;
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackageClasses = EmployeeRepository.class)
public class SpringDataJpaConfig {
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.baeldung.spring.data.persistence.springdata_jpa_difference.model");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
em.setJpaProperties(properties);
return em;
}
@Bean
public PlatformTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject());
return transactionManager;
}
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create()
.url("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1")
.driverClassName("org.h2.Driver")
.username("sa")
.password("sa")
.build();
}
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager entityManager) {
return new JPAQueryFactory((entityManager));
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee;
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
List<Employee> findByFirstName(String firstName);
@Query(value = "SELECT e FROM Employee e")
List<Employee> findAllEmployee(Sort sort);
}

View File

@ -0,0 +1,11 @@
package com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee;
@Repository
public interface EmployeeRepositoryPagingAndSort extends PagingAndSortingRepository<Employee, Long> {
}

View File

@ -0,0 +1,201 @@
package com.baeldung.spring.data.persistence.springdatajpadifference;
import static com.baeldung.spring.data.persistence.springdatajpadifference.TestUtils.employee;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import java.util.Arrays;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Root;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee;
import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee_;
public class JpaDaoIntegrationTest {
private final EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu-test");
private final EntityManager entityManager = emf.createEntityManager();
@Before
public void setup() {
deleteAllEmployees();
}
@Test
public void givenPersistedEmployee_whenFindById_thenEmployeeIsFound() {
Employee employee = employee("John", "Doe");
save(employee);
assertEquals(employee, entityManager.find(Employee.class, employee.getId()));
}
@Test
public void givenPersistedEmployee_whenFindByIdCriteriaQuery_thenEmployeeIsFound() {
Employee employee = employee("John", "Doe");
save(employee);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> root = criteriaQuery.from(Employee.class);
criteriaQuery.select(root);
criteriaQuery.where(criteriaBuilder.equal(root.get(Employee_.ID), employee.getId()));
assertEquals(employee, entityManager.createQuery(criteriaQuery)
.getSingleResult());
}
@Test
public void givenPersistedEmployee_whenFindByIdJpql_thenEmployeeIsFound() {
Employee employee = employee("John", "Doe");
save(employee);
Query jpqlQuery = entityManager.createQuery("SELECT e from Employee e WHERE e.id=:id");
jpqlQuery.setParameter("id", employee.getId());
assertEquals(employee, jpqlQuery.getSingleResult());
}
@Test
public void givenPersistedEmployee_whenFindByIdNamedQuery_thenEmployeeIsFound() {
Employee employee = employee("John", "Doe");
save(employee);
Query query = entityManager.createNamedQuery("Employee.findById");
query.setParameter(Employee_.ID, employee.getId());
assertEquals(employee, query.getSingleResult());
}
@Test
public void givenPersistedEmployee_whenFindWithPaginationAndSort_thenEmployeesAreFound() {
Employee john = employee("John", "Doe");
Employee bob = employee("Bob", "Smith");
Employee frank = employee("Frank", "Brown");
Employee james = employee("James", "Smith");
save(john);
save(bob);
save(frank);
save(james);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> root = criteriaQuery.from(Employee.class);
criteriaQuery.select(root);
criteriaQuery.orderBy(criteriaBuilder.asc(root.get(Employee_.FIRST_NAME)));
TypedQuery<Employee> query = entityManager.createQuery(criteriaQuery);
query.setFirstResult(0);
query.setMaxResults(3);
List<Employee> employeeList = query.getResultList();
assertEquals(Arrays.asList(bob, frank, james), employeeList);
}
@Test
public void givenPersistedEmployee_whenUpdateEmployeeEmail_thenEmployeeHasUpdatedEmail() {
Employee employee = employee("John", "Doe");
save(employee);
Employee employeeToUpdate = entityManager.find(Employee.class, employee.getId());
String updatedEmail = "email@gmail.com";
employeeToUpdate.setEmail(updatedEmail);
update(employeeToUpdate);
assertEquals(updatedEmail, entityManager.find(Employee.class, employee.getId())
.getEmail());
}
@Test
public void givenPersistedEmployee_whenUpdateEmployeeEmailWithCriteria_thenEmployeeHasUpdatedEmail() {
Employee employee = employee("John", "Doe");
save(employee);
String updatedEmail = "email@gmail.com";
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaUpdate<Employee> criteriaUpdate = criteriaBuilder.createCriteriaUpdate(Employee.class);
Root<Employee> root = criteriaUpdate.from(Employee.class);
criteriaUpdate.set(Employee_.EMAIL, updatedEmail);
criteriaUpdate.where(criteriaBuilder.equal(root.get(Employee_.ID), employee.getId()));
assertEquals(1, update(criteriaUpdate));
assertEquals(updatedEmail, entityManager.find(Employee.class, employee.getId())
.getEmail());
}
@Test
public void givenPersistedEmployee_whenRemoveEmployee_thenNoEmployeeIsFound() {
Employee employee = employee("John", "Doe");
save(employee);
delete(employee.getId());
assertNull(entityManager.find(Employee.class, employee.getId()));
}
private void deleteAllEmployees() {
entityManager.getTransaction()
.begin();
entityManager.createNativeQuery("DELETE from Employee")
.executeUpdate();
entityManager.getTransaction()
.commit();
}
public void save(Employee entity) {
entityManager.getTransaction()
.begin();
entityManager.persist(entity);
entityManager.getTransaction()
.commit();
}
public void update(Employee entity) {
entityManager.getTransaction()
.begin();
entityManager.merge(entity);
entityManager.getTransaction()
.commit();
}
public void delete(Long employee) {
entityManager.getTransaction()
.begin();
entityManager.remove(entityManager.find(Employee.class, employee));
entityManager.getTransaction()
.commit();
}
public int update(CriteriaUpdate<Employee> criteriaUpdate) {
entityManager.getTransaction()
.begin();
int result = entityManager.createQuery(criteriaUpdate)
.executeUpdate();
entityManager.getTransaction()
.commit();
entityManager.clear();
return result;
}
}

View File

@ -0,0 +1,153 @@
package com.baeldung.spring.data.persistence.springdatajpadifference;
import static com.baeldung.spring.data.persistence.springdatajpadifference.TestUtils.employee;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertFalse;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee;
import com.baeldung.spring.data.persistence.springdatajpadifference.model.QEmployee;
import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.config.SpringDataJpaConfig;
import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository.EmployeeRepository;
import com.baeldung.spring.data.persistence.springdatajpadifference.springdata.repository.EmployeeRepositoryPagingAndSort;
import com.querydsl.jpa.impl.JPAQueryFactory;
@ContextConfiguration(classes = SpringDataJpaConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@Rollback
public class SpringDataJpaIntegrationTest {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private EmployeeRepositoryPagingAndSort employeeRepositoryPagingAndSort;
@Autowired
private JPAQueryFactory jpaQueryFactory;
@Test
public void givenPersistedEmployee_whenFindById_thenEmployeeIsFound() {
Employee employee = employee("John", "Doe");
employeeRepository.save(employee);
assertEquals(Optional.of(employee), employeeRepository.findById(employee.getId()));
}
@Test
public void givenPersistedEmployee_whenFindByFirstName_thenEmployeeIsFound() {
Employee employee = employee("John", "Doe");
employeeRepository.save(employee);
assertEquals(employee, employeeRepository.findByFirstName(employee.getFirstName())
.get(0));
}
@Test
public void givenPersistedEmployee_whenUpdateEmployeeEmail_thenEmployeeHasUpdatedEmail() {
Employee employee = employee("John", "Doe");
employeeRepository.save(employee);
Employee employeeToUpdate = employeeRepository.findById(employee.getId())
.orElse(null);
assertNotNull(employeeToUpdate);
assertEquals(employee, employeeToUpdate);
String updatedEmail = "email@gmail.com";
employeeToUpdate.setEmail(updatedEmail);
employeeRepository.save(employeeToUpdate);
assertEquals(Optional.of(employeeToUpdate), employeeRepository.findById(employee.getId()));
}
@Test
public void givenPersistedEmployee_whenRemoveEmployee_thenNoEmployeeIsFound() {
Employee employee = employee("John", "Doe");
employeeRepository.save(employee);
Employee persistedEmployee = employeeRepository.findById(employee.getId())
.orElse(null);
assertNotNull(persistedEmployee);
employeeRepository.delete(persistedEmployee);
assertFalse(employeeRepository.findById(employee.getId())
.isPresent());
}
@Test
public void givenPersistedEmployees_whenFindSortedByFirstName_thenEmployeeAreFoundInOrder() {
Employee john = employee("John", "Doe");
Employee bob = employee("Bob", "Smith");
Employee frank = employee("Frank", "Brown");
employeeRepository.saveAll(Arrays.asList(john, bob, frank));
List<Employee> employees = employeeRepository.findAllEmployee(Sort.by("firstName"));
assertEquals(3, employees.size());
assertEquals(bob, employees.get(0));
assertEquals(frank, employees.get(1));
assertEquals(john, employees.get(2));
}
@Test
public void givenPersistedEmployee_whenFindByQueryDsl_thenEmployeeIsFound() {
Employee john = employee("John", "Doe");
Employee frank = employee("Frank", "Doe");
employeeRepository.saveAll(Arrays.asList(john, frank));
QEmployee employeePath = QEmployee.employee;
List<Employee> employees = jpaQueryFactory.selectFrom(employeePath)
.where(employeePath.firstName.eq("John"), employeePath.lastName.eq("Doe"))
.fetch();
assertEquals(1, employees.size());
assertEquals(john, employees.get(0));
}
@Test
public void givenPersistedEmployee_whenFindBySortAndPagingRepository_thenEmployeeAreFound() {
Employee john = employee("John", "Doe");
Employee bob = employee("Bob", "Smith");
Employee frank = employee("Frank", "Brown");
Employee jimmy = employee("Jimmy", "Armstrong");
employeeRepositoryPagingAndSort.saveAll(Arrays.asList(john, bob, frank, jimmy));
Pageable pageable = PageRequest.of(0, 2, Sort.by("firstName"));
Page<Employee> employees = employeeRepositoryPagingAndSort.findAll(pageable);
assertEquals(Arrays.asList(bob, frank), employees.get()
.collect(Collectors.toList()));
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung.spring.data.persistence.springdatajpadifference;
import com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee;
public class TestUtils {
public static Employee employee(String firstName, String lastname) {
Employee employee = new Employee();
employee.setFirstName(firstName);
employee.setLastName(lastname);
employee.setEmail(firstName + lastname + "@baeldung.com");
return employee;
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="pu-test">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.baeldung.spring.data.persistence.springdatajpadifference.model.Employee</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>