properties = new HashMap<>();
+ properties.put("javax.persistence.fetchgraph", entityGraph);
+ return em.find(Employee.class, id, properties);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java
new file mode 100644
index 0000000000..3b9aa2cc18
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/MultipleDbApplication.java
@@ -0,0 +1,14 @@
+package com.baeldung.multipledb;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class MultipleDbApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MultipleDbApplication.class, args);
+ }
+
+}
+
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java
new file mode 100644
index 0000000000..a6f8f0829f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductAutoConfiguration.java
@@ -0,0 +1,71 @@
+package com.baeldung.multipledb;
+
+import java.util.HashMap;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+
+/**
+ * By default, the persistence-multiple-db.properties file is read for
+ * non auto configuration in PersistenceProductConfiguration.
+ *
+ * If we need to use persistence-multiple-db-boot.properties and auto configuration
+ * then uncomment the below @Configuration class and comment out PersistenceProductConfiguration.
+ */
+//@Configuration
+@PropertySource({"classpath:persistence-multiple-db-boot.properties"})
+@EnableJpaRepositories(basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager")
+@Profile("!tc")
+public class PersistenceProductAutoConfiguration {
+ @Autowired
+ private Environment env;
+
+ public PersistenceProductAutoConfiguration() {
+ super();
+ }
+
+ //
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean productEntityManager() {
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(productDataSource());
+ em.setPackagesToScan("com.baeldung.multipledb.model.product");
+
+ final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ em.setJpaVendorAdapter(vendorAdapter);
+ final HashMap properties = new HashMap();
+ properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ em.setJpaPropertyMap(properties);
+
+ return em;
+ }
+
+ @Bean
+ @ConfigurationProperties(prefix="spring.second-datasource")
+ public DataSource productDataSource() {
+ return DataSourceBuilder.create().build();
+ }
+
+ @Bean
+ public PlatformTransactionManager productTransactionManager() {
+ final JpaTransactionManager transactionManager = new JpaTransactionManager();
+ transactionManager.setEntityManagerFactory(productEntityManager().getObject());
+ return transactionManager;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java
new file mode 100644
index 0000000000..bcf2cd84eb
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceProductConfiguration.java
@@ -0,0 +1,68 @@
+package com.baeldung.multipledb;
+
+import com.google.common.base.Preconditions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+
+@Configuration
+@PropertySource({"classpath:persistence-multiple-db.properties"})
+@EnableJpaRepositories(basePackages = "com.baeldung.multipledb.dao.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager")
+@Profile("!tc")
+public class PersistenceProductConfiguration {
+ @Autowired
+ private Environment env;
+
+ public PersistenceProductConfiguration() {
+ super();
+ }
+
+ //
+
+ @Bean
+ public LocalContainerEntityManagerFactoryBean productEntityManager() {
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(productDataSource());
+ em.setPackagesToScan("com.baeldung.multipledb.model.product");
+
+ final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ em.setJpaVendorAdapter(vendorAdapter);
+ final HashMap properties = new HashMap();
+ properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ em.setJpaPropertyMap(properties);
+
+ return em;
+ }
+
+ @Bean
+ public DataSource productDataSource() {
+ final DriverManagerDataSource dataSource = new DriverManagerDataSource();
+ dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
+ dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("product.jdbc.url")));
+ dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
+ dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
+
+ return dataSource;
+ }
+
+ @Bean
+ public PlatformTransactionManager productTransactionManager() {
+ final JpaTransactionManager transactionManager = new JpaTransactionManager();
+ transactionManager.setEntityManagerFactory(productEntityManager().getObject());
+ return transactionManager;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java
new file mode 100644
index 0000000000..e04a1621b2
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserAutoConfiguration.java
@@ -0,0 +1,75 @@
+package com.baeldung.multipledb;
+
+import java.util.HashMap;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.context.annotation.Profile;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+
+/**
+ * By default, the persistence-multiple-db.properties file is read for
+ * non auto configuration in PersistenceUserConfiguration.
+ *
+ * If we need to use persistence-multiple-db-boot.properties and auto configuration
+ * then uncomment the below @Configuration class and comment out PersistenceUserConfiguration.
+ */
+//@Configuration
+@PropertySource({"classpath:persistence-multiple-db-boot.properties"})
+@EnableJpaRepositories(basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager")
+@Profile("!tc")
+public class PersistenceUserAutoConfiguration {
+ @Autowired
+ private Environment env;
+
+ public PersistenceUserAutoConfiguration() {
+ super();
+ }
+
+ //
+
+ @Primary
+ @Bean
+ public LocalContainerEntityManagerFactoryBean userEntityManager() {
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(userDataSource());
+ em.setPackagesToScan("com.baeldung.multipledb.model.user");
+
+ final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ em.setJpaVendorAdapter(vendorAdapter);
+ final HashMap properties = new HashMap();
+ properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ em.setJpaPropertyMap(properties);
+
+ return em;
+ }
+
+ @Bean
+ @Primary
+ @ConfigurationProperties(prefix="spring.datasource")
+ public DataSource userDataSource() {
+ return DataSourceBuilder.create().build();
+ }
+
+ @Primary
+ @Bean
+ public PlatformTransactionManager userTransactionManager() {
+ final JpaTransactionManager transactionManager = new JpaTransactionManager();
+ transactionManager.setEntityManagerFactory(userEntityManager().getObject());
+ return transactionManager;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java
new file mode 100644
index 0000000000..6b48455c0c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/PersistenceUserConfiguration.java
@@ -0,0 +1,69 @@
+package com.baeldung.multipledb;
+
+import com.google.common.base.Preconditions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.*;
+import org.springframework.core.env.Environment;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.orm.jpa.JpaTransactionManager;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import javax.sql.DataSource;
+import java.util.HashMap;
+
+@Configuration
+@PropertySource({"classpath:persistence-multiple-db.properties"})
+@EnableJpaRepositories(basePackages = "com.baeldung.multipledb.dao.user", entityManagerFactoryRef = "userEntityManager", transactionManagerRef = "userTransactionManager")
+@Profile("!tc")
+public class PersistenceUserConfiguration {
+ @Autowired
+ private Environment env;
+
+ public PersistenceUserConfiguration() {
+ super();
+ }
+
+ //
+
+ @Primary
+ @Bean
+ public LocalContainerEntityManagerFactoryBean userEntityManager() {
+ System.out.println("loading config");
+ final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
+ em.setDataSource(userDataSource());
+ em.setPackagesToScan("com.baeldung.multipledb.model.user");
+
+ final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
+ em.setJpaVendorAdapter(vendorAdapter);
+ final HashMap properties = new HashMap();
+ properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
+ properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
+ em.setJpaPropertyMap(properties);
+
+ return em;
+ }
+
+ @Primary
+ @Bean
+ public DataSource userDataSource() {
+ final DriverManagerDataSource dataSource = new DriverManagerDataSource();
+ dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
+ dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("user.jdbc.url")));
+ dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
+ dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
+
+ return dataSource;
+ }
+
+ @Primary
+ @Bean
+ public PlatformTransactionManager userTransactionManager() {
+ final JpaTransactionManager transactionManager = new JpaTransactionManager();
+ transactionManager.setEntityManagerFactory(userEntityManager().getObject());
+ return transactionManager;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java
new file mode 100755
index 0000000000..f1256e2c72
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/product/ProductRepository.java
@@ -0,0 +1,14 @@
+package com.baeldung.multipledb.dao.product;
+
+import java.util.List;
+
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.repository.PagingAndSortingRepository;
+
+import com.baeldung.multipledb.model.product.Product;
+
+public interface ProductRepository extends PagingAndSortingRepository {
+
+
+ List findAllByPrice(double price, Pageable pageable);
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java
new file mode 100644
index 0000000000..ae37fde20d
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/PossessionRepository.java
@@ -0,0 +1,9 @@
+package com.baeldung.multipledb.dao.user;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.baeldung.multipledb.model.user.PossessionMultipleDB;
+
+public interface PossessionRepository extends JpaRepository {
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java
new file mode 100644
index 0000000000..267a61a93f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/dao/user/UserRepository.java
@@ -0,0 +1,8 @@
+package com.baeldung.multipledb.dao.user;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import com.baeldung.multipledb.model.user.UserMultipleDB;
+
+public interface UserRepository extends JpaRepository {
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/product/Product.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/product/Product.java
new file mode 100755
index 0000000000..eaf471043c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/product/Product.java
@@ -0,0 +1,67 @@
+package com.baeldung.multipledb.model.product;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(schema = "products")
+public class Product {
+
+ @Id
+ private int id;
+
+ private String name;
+
+ private double price;
+
+ public Product() {
+ super();
+ }
+
+ private Product(int id, String name, double price) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.price = price;
+ }
+
+ public static Product from(int id, String name, double price) {
+ return new Product(id, name, price);
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(final int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(final double price) {
+ this.price = price;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Product [name=")
+ .append(name)
+ .append(", id=")
+ .append(id)
+ .append("]");
+ return builder.toString();
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/PossessionMultipleDB.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/PossessionMultipleDB.java
new file mode 100644
index 0000000000..a6a3c88bd0
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/PossessionMultipleDB.java
@@ -0,0 +1,82 @@
+package com.baeldung.multipledb.model.user;
+
+import javax.persistence.*;
+
+@Entity
+@Table
+public class PossessionMultipleDB {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ private String name;
+
+ public PossessionMultipleDB() {
+ super();
+ }
+
+ public PossessionMultipleDB(final String name) {
+ super();
+
+ this.name = name;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(final int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = (prime * result) + (int) (id ^ (id >>> 32));
+ result = (prime * result) + ((name == null) ? 0 : name.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ final PossessionMultipleDB other = (PossessionMultipleDB) obj;
+ if (id != other.id) {
+ return false;
+ }
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if (!name.equals(other.name)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Possesion [id=").append(id).append(", name=").append(name).append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/UserMultipleDB.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/UserMultipleDB.java
new file mode 100644
index 0000000000..c7cd07f7a1
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/multipledb/model/user/UserMultipleDB.java
@@ -0,0 +1,88 @@
+package com.baeldung.multipledb.model.user;
+
+import javax.persistence.*;
+
+import java.util.List;
+
+@Entity
+@Table(name = "users")
+public class UserMultipleDB {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private int id;
+ private String name;
+ private int age;
+ @Column(unique = true, nullable = false)
+ private String email;
+ private Integer status;
+
+ @OneToMany
+ List possessionList;
+
+ public UserMultipleDB() {
+ super();
+ }
+
+ public UserMultipleDB(String name, String email, Integer status) {
+ this.name = name;
+ this.email = email;
+ this.status = status;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(final int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(final String email) {
+ this.email = email;
+ }
+
+ public Integer getStatus() {
+ return status;
+ }
+
+ public void setStatus(Integer status) {
+ this.status = status;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(final int age) {
+ this.age = age;
+ }
+
+ public List getPossessionList() {
+ return possessionList;
+ }
+
+ public void setPossessionList(List possessionList) {
+ this.possessionList = possessionList;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append("User [name=").append(name).append(", id=").append(id).append("]");
+ return builder.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/Person.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/Person.java
new file mode 100644
index 0000000000..cfb6e67c2c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/Person.java
@@ -0,0 +1,35 @@
+package com.baeldung.namingstrategy;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+@Entity
+public class Person {
+ @Id
+ private Long id;
+
+ private String firstName;
+
+ private String lastName;
+
+ public Person() {}
+
+ public Person(Long id, String firstName, String lastName) {
+ this.id = id;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public Long id() {
+ return id;
+ }
+
+ public String firstName() {
+ return firstName;
+ }
+
+ public String lastName() {
+ return lastName;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/PersonRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/PersonRepository.java
new file mode 100644
index 0000000000..3c7c25bbcb
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/PersonRepository.java
@@ -0,0 +1,6 @@
+package com.baeldung.namingstrategy;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface PersonRepository extends JpaRepository {
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategy.java
new file mode 100644
index 0000000000..16b01e50e3
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class QuotedLowerCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toLowerCase(), true);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategy.java
new file mode 100644
index 0000000000..3cb62aa5a2
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class QuotedUpperCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toUpperCase(), true);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/SpringDataJpaNamingConventionApplication.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/SpringDataJpaNamingConventionApplication.java
new file mode 100644
index 0000000000..f223015db8
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/SpringDataJpaNamingConventionApplication.java
@@ -0,0 +1,7 @@
+package com.baeldung.namingstrategy;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SpringDataJpaNamingConventionApplication {
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategy.java
new file mode 100644
index 0000000000..69e96aee27
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class UnquotedLowerCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toLowerCase(), false);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategy.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategy.java
new file mode 100644
index 0000000000..cb87af10f4
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/namingstrategy/UnquotedUpperCaseNamingStrategy.java
@@ -0,0 +1,12 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.boot.model.naming.Identifier;
+import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
+import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;
+
+public class UnquotedUpperCaseNamingStrategy extends SpringPhysicalNamingStrategy {
+ @Override
+ protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
+ return new Identifier(name.toUpperCase(), false);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/OsivApplication.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/OsivApplication.java
new file mode 100644
index 0000000000..4cfcf83e56
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/OsivApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.osiv;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class OsivApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(OsivApplication.class, args);
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/model/BasicUser.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/model/BasicUser.java
new file mode 100644
index 0000000000..98f4e379d4
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/model/BasicUser.java
@@ -0,0 +1,42 @@
+package com.baeldung.osiv.model;
+
+import javax.persistence.*;
+import java.util.Set;
+
+@Entity
+@Table(name = "users")
+public class BasicUser {
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String username;
+
+ @ElementCollection
+ private Set permissions;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public Set getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(Set permissions) {
+ this.permissions = permissions;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/repository/BasicUserRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/repository/BasicUserRepository.java
new file mode 100644
index 0000000000..e8d5955d91
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/repository/BasicUserRepository.java
@@ -0,0 +1,19 @@
+package com.baeldung.osiv.repository;
+
+import java.util.Optional;
+
+import org.springframework.data.jpa.repository.EntityGraph;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.osiv.model.BasicUser;
+
+@Repository
+@Transactional
+public interface BasicUserRepository extends JpaRepository {
+
+ @EntityGraph(attributePaths = "permissions")
+ Optional findDetailedByUsername(String username);
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/service/SimpleUserService.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/service/SimpleUserService.java
new file mode 100644
index 0000000000..1de51678d5
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/service/SimpleUserService.java
@@ -0,0 +1,25 @@
+package com.baeldung.osiv.service;
+
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.osiv.model.BasicUser;
+import com.baeldung.osiv.repository.BasicUserRepository;
+
+@Service
+public class SimpleUserService implements UserService {
+
+ private final BasicUserRepository userRepository;
+
+ public SimpleUserService(BasicUserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ @Override
+ @Transactional(readOnly = true)
+ public Optional findOne(String username) {
+ return userRepository.findDetailedByUsername(username);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/service/UserService.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/service/UserService.java
new file mode 100644
index 0000000000..3d089fa41b
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/service/UserService.java
@@ -0,0 +1,9 @@
+package com.baeldung.osiv.service;
+
+import com.baeldung.osiv.model.BasicUser;
+
+import java.util.Optional;
+
+public interface UserService {
+ Optional findOne(String username);
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/web/DetailedUserDto.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/web/DetailedUserDto.java
new file mode 100644
index 0000000000..fd2882c2d5
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/web/DetailedUserDto.java
@@ -0,0 +1,45 @@
+package com.baeldung.osiv.web;
+
+import com.baeldung.osiv.model.BasicUser;
+
+import java.util.Set;
+
+public class DetailedUserDto {
+
+ private Long id;
+ private String username;
+ private Set permissions;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public Set getPermissions() {
+ return permissions;
+ }
+
+ public void setPermissions(Set permissions) {
+ this.permissions = permissions;
+ }
+
+ public static DetailedUserDto fromEntity(BasicUser user) {
+ DetailedUserDto detailed = new DetailedUserDto();
+ detailed.setId(user.getId());
+ detailed.setUsername(user.getUsername());
+ detailed.setPermissions(user.getPermissions());
+
+ return detailed;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/web/UserController.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/web/UserController.java
new file mode 100644
index 0000000000..5466b95166
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/osiv/web/UserController.java
@@ -0,0 +1,27 @@
+package com.baeldung.osiv.web;
+
+import com.baeldung.osiv.service.UserService;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/users")
+public class UserController {
+
+ private final UserService userService;
+
+ public UserController(UserService userService) {
+ this.userService = userService;
+ }
+
+ @GetMapping("/{username}")
+ public ResponseEntity> findOne(@PathVariable String username) {
+ return userService.findOne(username)
+ .map(DetailedUserDto::fromEntity)
+ .map(ResponseEntity::ok)
+ .orElse(ResponseEntity.notFound().build());
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java
new file mode 100644
index 0000000000..a750fcadf7
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/PartialUpdateApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.partialupdate;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class PartialUpdateApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(PartialUpdateApplication.class, args);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java
new file mode 100644
index 0000000000..352e361bd9
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/ContactPhone.java
@@ -0,0 +1,22 @@
+package com.baeldung.partialupdate.model;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class ContactPhone {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ public long id;
+ @Column(nullable=false)
+ public long customerId;
+ public String phone;
+
+ @Override
+ public String toString() {
+ return phone;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/Customer.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/Customer.java
new file mode 100644
index 0000000000..b19d0b7952
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/Customer.java
@@ -0,0 +1,23 @@
+package com.baeldung.partialupdate.model;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Customer {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ public long id;
+ public String name;
+ public String phone;
+ //...
+ public String phone99;
+
+ @Override public String toString() {
+ return String.format("Customer %s, Phone: %s",
+ this.name, this.phone);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java
new file mode 100644
index 0000000000..0ecf206d9a
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/CustomerDto.java
@@ -0,0 +1,31 @@
+package com.baeldung.partialupdate.model;
+
+public class CustomerDto {
+ private long id;
+ public String name;
+ public String phone;
+ //...
+ private String phone99;
+
+ public CustomerDto(long id) {
+ this.id = id;
+ }
+
+ public CustomerDto(Customer c) {
+ this.id = c.id;
+ this.name = c.name;
+ this.phone = c.phone;
+ }
+
+ public long getId() {
+ return this.id;
+ }
+
+ public Customer convertToEntity() {
+ Customer c = new Customer();
+ c.id = id;
+ c.name = name;
+ c.phone = phone;
+ return c;
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java
new file mode 100644
index 0000000000..dd053a963d
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/model/CustomerStructured.java
@@ -0,0 +1,27 @@
+package com.baeldung.partialupdate.model;
+
+import java.util.List;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+
+@Entity
+public class CustomerStructured {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ public long id;
+ public String name;
+ @OneToMany(fetch = FetchType.EAGER, targetEntity = ContactPhone.class, mappedBy = "customerId")
+ public List contactPhones;
+
+ @Override public String toString() {
+ return String.format("Customer %s, Phone: %s",
+ this.name, this.contactPhones.stream()
+ .map(e -> e.toString()).reduce("", String::concat));
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java
new file mode 100644
index 0000000000..4668181e05
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/ContactPhoneRepository.java
@@ -0,0 +1,12 @@
+package com.baeldung.partialupdate.repository;
+
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+import com.baeldung.partialupdate.model.ContactPhone;
+
+@Repository
+public interface ContactPhoneRepository extends CrudRepository {
+ ContactPhone findById(long id);
+ ContactPhone findByCustomerId(long id);
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java
new file mode 100644
index 0000000000..43e61df8ab
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/CustomerRepository.java
@@ -0,0 +1,18 @@
+package com.baeldung.partialupdate.repository;
+
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import com.baeldung.partialupdate.model.Customer;
+
+@Repository
+public interface CustomerRepository extends CrudRepository {
+ Customer findById(long id);
+
+ @Modifying
+ @Query("update Customer u set u.phone = :phone where u.id = :id")
+ void updatePhone(@Param(value = "id") long id, @Param(value = "phone") String phone);
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/CustomerStructuredRepository.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/CustomerStructuredRepository.java
new file mode 100644
index 0000000000..0f9fd1e92e
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/repository/CustomerStructuredRepository.java
@@ -0,0 +1,11 @@
+package com.baeldung.partialupdate.repository;
+
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+import com.baeldung.partialupdate.model.CustomerStructured;
+
+@Repository
+public interface CustomerStructuredRepository extends CrudRepository {
+ CustomerStructured findById(long id);
+}
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/service/CustomerService.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/service/CustomerService.java
new file mode 100644
index 0000000000..9da97a7775
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/service/CustomerService.java
@@ -0,0 +1,87 @@
+package com.baeldung.partialupdate.service;
+
+import javax.transaction.Transactional;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.baeldung.partialupdate.model.ContactPhone;
+import com.baeldung.partialupdate.model.Customer;
+import com.baeldung.partialupdate.model.CustomerDto;
+import com.baeldung.partialupdate.model.CustomerStructured;
+import com.baeldung.partialupdate.repository.ContactPhoneRepository;
+import com.baeldung.partialupdate.repository.CustomerRepository;
+import com.baeldung.partialupdate.repository.CustomerStructuredRepository;
+import com.baeldung.partialupdate.util.CustomerMapper;
+
+@Service
+@Transactional
+public class CustomerService {
+
+ @Autowired
+ CustomerRepository repo;
+ @Autowired
+ CustomerStructuredRepository repo2;
+ @Autowired
+ ContactPhoneRepository repo3;
+ @Autowired
+ CustomerMapper mapper;
+
+ public Customer getCustomer(long id) {
+ return repo.findById(id);
+ }
+
+ public void updateCustomerWithCustomQuery(long id, String phone) {
+ repo.updatePhone(id, phone);
+ }
+
+ public Customer addCustomer(String name) {
+ Customer myCustomer = new Customer();
+ myCustomer.name = name;
+ repo.save(myCustomer);
+ return myCustomer;
+ }
+
+ public Customer updateCustomer(long id, String phone) {
+ Customer myCustomer = repo.findById(id);
+ myCustomer.phone = phone;
+ repo.save(myCustomer);
+ return myCustomer;
+ }
+
+ public Customer addCustomer(CustomerDto dto) {
+ Customer myCustomer = new Customer();
+ mapper.updateCustomerFromDto(dto, myCustomer);
+ repo.save(myCustomer);
+ return myCustomer;
+ }
+
+ public Customer updateCustomer(CustomerDto dto) {
+ Customer myCustomer = repo.findById(dto.getId());
+ mapper.updateCustomerFromDto(dto, myCustomer);
+ repo.save(myCustomer);
+ return myCustomer;
+ }
+
+ public CustomerStructured addCustomerStructured(String name) {
+ CustomerStructured myCustomer = new CustomerStructured();
+ myCustomer.name = name;
+ repo2.save(myCustomer);
+ return myCustomer;
+ }
+
+ public void addCustomerPhone(long customerId, String phone) {
+ ContactPhone myPhone = new ContactPhone();
+ myPhone.phone = phone;
+ myPhone.customerId = customerId;
+ repo3.save(myPhone);
+ }
+
+ public CustomerStructured updateCustomerStructured(long id, String name) {
+ CustomerStructured myCustomer = repo2.findById(id);
+ myCustomer.name = name;
+ repo2.save(myCustomer);
+ return myCustomer;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/util/CustomerMapper.java b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/util/CustomerMapper.java
new file mode 100644
index 0000000000..8a666e3e6c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/java/com/baeldung/partialupdate/util/CustomerMapper.java
@@ -0,0 +1,15 @@
+package com.baeldung.partialupdate.util;
+
+import org.mapstruct.BeanMapping;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.NullValuePropertyMappingStrategy;
+
+import com.baeldung.partialupdate.model.Customer;
+import com.baeldung.partialupdate.model.CustomerDto;
+
+@Mapper(componentModel = "spring")
+public interface CustomerMapper {
+ @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
+ void updateCustomerFromDto(CustomerDto dto, @MappingTarget Customer entity);
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties
new file mode 100644
index 0000000000..29326c6061
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/application.properties
@@ -0,0 +1,16 @@
+
+spring.datasource.url=jdbc:h2:mem:baeldung
+
+# JPA-Schema-Generation
+# Use below configuration to generate database schema create commands based on the entity models
+# and export them into the create.sql file
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=create.sql
+#spring.jpa.properties.javax.persistence.schema-generation.scripts.create-source=metadata
+#spring.jpa.properties.hibernate.format_sql=true
+
+spring.jpa.show-sql=true
+spring.main.allow-bean-definition-overriding=true
+
+#hibernate.dialect=org.hibernate.dialect.H2Dialect
+spring.jpa.properties.hibernate.id.new_generator_mappings=false
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db-boot.properties b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db-boot.properties
new file mode 100644
index 0000000000..ffca79b3f5
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db-boot.properties
@@ -0,0 +1,11 @@
+hibernate.hbm2ddl.auto=create-drop
+hibernate.cache.use_second_level_cache=false
+hibernate.cache.use_query_cache=false
+
+spring.datasource.jdbcUrl=jdbc:h2:mem:spring_jpa_user;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS USERS
+spring.datasource.username=sa
+spring.datasource.password=sa
+
+spring.second-datasource.jdbcUrl=jdbc:h2:mem:spring_jpa_product;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS PRODUCTS
+spring.second-datasource.username=sa
+spring.second-datasource.password=sa
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db.properties b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db.properties
new file mode 100644
index 0000000000..75534e8a54
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/main/resources/persistence-multiple-db.properties
@@ -0,0 +1,13 @@
+# jdbc.X
+jdbc.driverClassName=org.h2.Driver
+user.jdbc.url=jdbc:h2:mem:spring_jpa_user;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS USERS
+product.jdbc.url=jdbc:h2:mem:spring_jpa_product;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS PRODUCTS
+jdbc.user=sa
+jdbc.pass=sa
+
+# hibernate.X
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+hibernate.show_sql=false
+hibernate.hbm2ddl.auto=create-drop
+hibernate.cache.use_second_level_cache=false
+hibernate.cache.use_query_cache=false
\ No newline at end of file
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringContextTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringContextTest.java
new file mode 100644
index 0000000000..eaccf4acba
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringContextTest.java
@@ -0,0 +1,17 @@
+package com.baeldung;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import com.baeldung.boot.Application;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+public class SpringContextTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringJpaContextIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringJpaContextIntegrationTest.java
new file mode 100644
index 0000000000..f3697bf39f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/SpringJpaContextIntegrationTest.java
@@ -0,0 +1,25 @@
+package com.baeldung;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import com.baeldung.boot.Application;
+import com.baeldung.boot.config.PersistenceConfiguration;
+import com.baeldung.multipledb.PersistenceProductConfiguration;
+import com.baeldung.multipledb.PersistenceUserConfiguration;
+
+@RunWith(SpringRunner.class)
+@DataJpaTest(excludeAutoConfiguration = {
+ PersistenceConfiguration.class,
+ PersistenceUserConfiguration.class,
+ PersistenceProductConfiguration.class })
+@ContextConfiguration(classes = Application.class)
+public class SpringJpaContextIntegrationTest {
+
+ @Test
+ public void whenSpringContextIsBootstrapped_thenNoExceptions() {
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java
new file mode 100644
index 0000000000..b2581b8034
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryCommon.java
@@ -0,0 +1,545 @@
+package com.baeldung.boot.daos;
+
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.jpa.domain.JpaSort;
+import org.springframework.data.mapping.PropertyReferenceException;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.boot.daos.user.UserRepository;
+import com.baeldung.boot.domain.User;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.*;
+
+public class UserRepositoryCommon {
+
+ final String USER_EMAIL = "email@example.com";
+ final String USER_EMAIL2 = "email2@example.com";
+ final String USER_EMAIL3 = "email3@example.com";
+ final String USER_EMAIL4 = "email4@example.com";
+ final Integer INACTIVE_STATUS = 0;
+ final Integer ACTIVE_STATUS = 1;
+ final String USER_EMAIL5 = "email5@example.com";
+ final String USER_EMAIL6 = "email6@example.com";
+ final String USER_NAME_ADAM = "Adam";
+ final String USER_NAME_PETER = "Peter";
+
+ @Autowired
+ protected UserRepository userRepository;
+ @Autowired
+ private EntityManager entityManager;
+
+ @Test
+ @Transactional
+ public void givenUsersWithSameNameInDB_WhenFindAllByName_ThenReturnStreamOfUsers() {
+ User user1 = new User();
+ user1.setName(USER_NAME_ADAM);
+ user1.setEmail(USER_EMAIL);
+ userRepository.save(user1);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_ADAM);
+ user2.setEmail(USER_EMAIL2);
+ userRepository.save(user2);
+
+ User user3 = new User();
+ user3.setName(USER_NAME_ADAM);
+ user3.setEmail(USER_EMAIL3);
+ userRepository.save(user3);
+
+ User user4 = new User();
+ user4.setName("SAMPLE");
+ user4.setEmail(USER_EMAIL4);
+ userRepository.save(user4);
+
+ try (Stream foundUsersStream = userRepository.findAllByName(USER_NAME_ADAM)) {
+ assertThat(foundUsersStream.count()).isEqualTo(3l);
+ }
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindAllWithQueryAnnotation_ThenReturnCollectionWithActiveUsers() {
+ User user1 = new User();
+ user1.setName(USER_NAME_ADAM);
+ user1.setEmail(USER_EMAIL);
+ user1.setStatus(ACTIVE_STATUS);
+ userRepository.save(user1);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_ADAM);
+ user2.setEmail(USER_EMAIL2);
+ user2.setStatus(ACTIVE_STATUS);
+ userRepository.save(user2);
+
+ User user3 = new User();
+ user3.setName(USER_NAME_ADAM);
+ user3.setEmail(USER_EMAIL3);
+ user3.setStatus(INACTIVE_STATUS);
+ userRepository.save(user3);
+
+ Collection allActiveUsers = userRepository.findAllActiveUsers();
+
+ assertThat(allActiveUsers.size()).isEqualTo(2);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindAllWithQueryAnnotationNative_ThenReturnCollectionWithActiveUsers() {
+ User user1 = new User();
+ user1.setName(USER_NAME_ADAM);
+ user1.setEmail(USER_EMAIL);
+ user1.setStatus(ACTIVE_STATUS);
+ userRepository.save(user1);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_ADAM);
+ user2.setEmail(USER_EMAIL2);
+ user2.setStatus(ACTIVE_STATUS);
+ userRepository.save(user2);
+
+ User user3 = new User();
+ user3.setName(USER_NAME_ADAM);
+ user3.setEmail(USER_EMAIL3);
+ user3.setStatus(INACTIVE_STATUS);
+ userRepository.save(user3);
+
+ Collection allActiveUsers = userRepository.findAllActiveUsersNative();
+
+ assertThat(allActiveUsers.size()).isEqualTo(2);
+ }
+
+ @Test
+ public void givenUserInDB_WhenFindUserByStatusWithQueryAnnotation_ThenReturnActiveUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User userByStatus = userRepository.findUserByStatus(ACTIVE_STATUS);
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUserInDB_WhenFindUserByStatusWithQueryAnnotationNative_ThenReturnActiveUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User userByStatus = userRepository.findUserByStatusNative(ACTIVE_STATUS);
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindUserByStatusAndNameWithQueryAnnotationIndexedParams_ThenReturnOneUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_PETER);
+ user2.setEmail(USER_EMAIL2);
+ user2.setStatus(ACTIVE_STATUS);
+ userRepository.save(user2);
+
+ User userByStatus = userRepository.findUserByStatusAndName(ACTIVE_STATUS, USER_NAME_ADAM);
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindUserByStatusAndNameWithQueryAnnotationNamedParams_ThenReturnOneUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_PETER);
+ user2.setEmail(USER_EMAIL2);
+ user2.setStatus(ACTIVE_STATUS);
+ userRepository.save(user2);
+
+ User userByStatus = userRepository.findUserByStatusAndNameNamedParams(ACTIVE_STATUS, USER_NAME_ADAM);
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindUserByStatusAndNameWithQueryAnnotationNativeNamedParams_ThenReturnOneUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_PETER);
+ user2.setEmail(USER_EMAIL2);
+ user2.setStatus(ACTIVE_STATUS);
+ userRepository.save(user2);
+
+ User userByStatus = userRepository.findUserByStatusAndNameNamedParamsNative(ACTIVE_STATUS, USER_NAME_ADAM);
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindUserByStatusAndNameWithQueryAnnotationNamedParamsCustomNames_ThenReturnOneUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_PETER);
+ user2.setEmail(USER_EMAIL2);
+ user2.setStatus(ACTIVE_STATUS);
+ userRepository.save(user2);
+
+ User userByStatus = userRepository.findUserByUserStatusAndUserName(ACTIVE_STATUS, USER_NAME_ADAM);
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindUserByNameLikeWithQueryAnnotationIndexedParams_ThenReturnUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User userByStatus = userRepository.findUserByNameLike("Ad");
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindUserByNameLikeWithQueryAnnotationNamedParams_ThenReturnUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User userByStatus = userRepository.findUserByNameLikeNamedParam("Ad");
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindUserByNameLikeWithQueryAnnotationNative_ThenReturnUser() {
+ User user = new User();
+ user.setName(USER_NAME_ADAM);
+ user.setEmail(USER_EMAIL);
+ user.setStatus(ACTIVE_STATUS);
+ userRepository.save(user);
+
+ User userByStatus = userRepository.findUserByNameLikeNative("Ad");
+
+ assertThat(userByStatus.getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindAllWithSortByName_ThenReturnUsersSorted() {
+ userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS));
+
+ List usersSortByName = userRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));
+
+ assertThat(usersSortByName.get(0)
+ .getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test(expected = PropertyReferenceException.class)
+ public void givenUsersInDB_WhenFindAllSortWithFunction_ThenThrowException() {
+ userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS));
+
+ userRepository.findAll(Sort.by(Sort.Direction.ASC, "name"));
+
+ List usersSortByNameLength = userRepository.findAll(Sort.by("LENGTH(name)"));
+
+ assertThat(usersSortByNameLength.get(0)
+ .getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindAllSortWithFunctionQueryAnnotationJPQL_ThenReturnUsersSorted() {
+ userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS));
+
+ userRepository.findAllUsers(Sort.by("name"));
+
+ List usersSortByNameLength = userRepository.findAllUsers(JpaSort.unsafe("LENGTH(name)"));
+
+ assertThat(usersSortByNameLength.get(0)
+ .getName()).isEqualTo(USER_NAME_ADAM);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindAllWithPageRequestQueryAnnotationJPQL_ThenReturnPageOfUsers() {
+ userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL4, INACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE2", LocalDate.now(), USER_EMAIL5, INACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL6, INACTIVE_STATUS));
+
+ Page usersPage = userRepository.findAllUsersWithPagination(PageRequest.of(1, 3));
+
+ assertThat(usersPage.getContent()
+ .get(0)
+ .getName()).isEqualTo("SAMPLE1");
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindAllWithPageRequestQueryAnnotationNative_ThenReturnPageOfUsers() {
+ userRepository.save(new User(USER_NAME_ADAM, LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User(USER_NAME_PETER, LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, INACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL4, INACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE2", LocalDate.now(), USER_EMAIL5, INACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL6, INACTIVE_STATUS));
+
+ Page usersSortByNameLength = userRepository.findAllUsersWithPaginationNative(PageRequest.of(1, 3));
+
+ assertThat(usersSortByNameLength.getContent()
+ .get(0)
+ .getName()).isEqualTo(USER_NAME_PETER);
+ }
+
+ @Test
+ @Transactional
+ public void givenUsersInDB_WhenUpdateStatusForNameModifyingQueryAnnotationJPQL_ThenModifyMatchingUsers() {
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS));
+
+ int updatedUsersSize = userRepository.updateUserSetStatusForName(INACTIVE_STATUS, "SAMPLE");
+
+ assertThat(updatedUsersSize).isEqualTo(2);
+ }
+
+ @Test
+ public void givenUsersInDB_WhenFindByEmailsWithDynamicQuery_ThenReturnCollection() {
+
+ User user1 = new User();
+ user1.setEmail(USER_EMAIL);
+ userRepository.save(user1);
+
+ User user2 = new User();
+ user2.setEmail(USER_EMAIL2);
+ userRepository.save(user2);
+
+ User user3 = new User();
+ user3.setEmail(USER_EMAIL3);
+ userRepository.save(user3);
+
+ Set emails = new HashSet<>();
+ emails.add(USER_EMAIL2);
+ emails.add(USER_EMAIL3);
+
+ Collection usersWithEmails = userRepository.findUserByEmails(emails);
+
+ assertThat(usersWithEmails.size()).isEqualTo(2);
+ }
+
+ @Test
+ public void givenUsersInDBWhenFindByNameListReturnCollection() {
+
+ User user1 = new User();
+ user1.setName(USER_NAME_ADAM);
+ user1.setEmail(USER_EMAIL);
+ userRepository.save(user1);
+
+ User user2 = new User();
+ user2.setName(USER_NAME_PETER);
+ user2.setEmail(USER_EMAIL2);
+ userRepository.save(user2);
+
+ List names = Arrays.asList(USER_NAME_ADAM, USER_NAME_PETER);
+
+ List usersWithNames = userRepository.findUserByNameList(names);
+
+ assertThat(usersWithNames.size()).isEqualTo(2);
+ }
+
+
+ @Test
+ @Transactional
+ public void whenInsertedWithQuery_ThenUserIsPersisted() {
+ userRepository.insertUser(USER_NAME_ADAM, 1, USER_EMAIL, ACTIVE_STATUS, true);
+ userRepository.insertUser(USER_NAME_PETER, 1, USER_EMAIL2, ACTIVE_STATUS, true);
+
+ User userAdam = userRepository.findUserByNameLike(USER_NAME_ADAM);
+ User userPeter = userRepository.findUserByNameLike(USER_NAME_PETER);
+
+ assertThat(userAdam).isNotNull();
+ assertThat(userAdam.getEmail()).isEqualTo(USER_EMAIL);
+ assertThat(userPeter).isNotNull();
+ assertThat(userPeter.getEmail()).isEqualTo(USER_EMAIL2);
+ }
+
+
+ @Test
+ @Transactional
+ public void givenTwoUsers_whenFindByNameUsr01_ThenUserUsr01() {
+ User usr01 = new User("usr01", LocalDate.now(), "usr01@baeldung.com", 1);
+ User usr02 = new User("usr02", LocalDate.now(), "usr02@baeldung.com", 1);
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ try (Stream users = userRepository.findAllByName("usr01")) {
+ assertTrue(users.allMatch(usr -> usr.equals(usr01)));
+ }
+ }
+
+ @Test
+ @Transactional
+ public void givenTwoUsers_whenFindByNameUsr00_ThenNoUsers() {
+ User usr01 = new User("usr01", LocalDate.now(), "usr01@baeldung.com", 1);
+ User usr02 = new User("usr02", LocalDate.now(), "usr02@baeldung.com", 1);
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ try (Stream users = userRepository.findAllByName("usr00")) {
+ assertEquals(0, users.count());
+ }
+ }
+
+ @Test
+ public void givenTwoUsers_whenFindUsersWithGmailAddress_ThenUserUsr02() {
+ User usr01 = new User("usr01", LocalDate.now(), "usr01@baeldung.com", 1);
+ User usr02 = new User("usr02", LocalDate.now(), "usr02@gmail.com", 1);
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ List users = userRepository.findUsersWithGmailAddress();
+ assertEquals(1, users.size());
+ assertEquals(usr02, users.get(0));
+ }
+
+ @Test
+ @Transactional
+ public void givenTwoUsers_whenDeleteAllByCreationDateAfter_ThenOneUserRemains() {
+ User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1);
+ User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.com", 1);
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ userRepository.deleteAllByCreationDateAfter(LocalDate.of(2018, 5, 1));
+
+ List users = userRepository.findAll();
+
+ assertEquals(1, users.size());
+ assertEquals(usr01, users.get(0));
+ }
+
+ @Test
+ public void givenTwoUsers_whenFindAllUsersByPredicates_ThenUserUsr01() {
+ User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1);
+ User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.org", 1);
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ List> predicates = new ArrayList<>();
+ predicates.add(usr -> usr.getCreationDate().isAfter(LocalDate.of(2017, 12, 31)));
+ predicates.add(usr -> usr.getEmail().endsWith(".com"));
+
+ List users = userRepository.findAllUsersByPredicates(predicates);
+
+ assertEquals(1, users.size());
+ assertEquals(usr01, users.get(0));
+ }
+
+ @Test
+ @Transactional
+ public void givenTwoUsers_whenDeactivateUsersNotLoggedInSince_ThenUserUsr02Deactivated() {
+ User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1);
+ usr01.setLastLoginDate(LocalDate.now());
+ User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.org", 1);
+ usr02.setLastLoginDate(LocalDate.of(2018, 7, 20));
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ userRepository.deactivateUsersNotLoggedInSince(LocalDate.of(2018, 8, 1));
+
+ List users = userRepository.findAllUsers(Sort.by(Sort.Order.asc("name")));
+ assertTrue(users.get(0).isActive());
+ assertFalse(users.get(1).isActive());
+ }
+
+ @Test
+ @Transactional
+ public void givenTwoUsers_whenDeleteDeactivatedUsers_ThenUserUsr02Deleted() {
+ User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1);
+ usr01.setLastLoginDate(LocalDate.now());
+ User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.com", 0);
+ usr02.setLastLoginDate(LocalDate.of(2018, 7, 20));
+ usr02.setActive(false);
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ int deletedUsersCount = userRepository.deleteDeactivatedUsers();
+
+ List users = userRepository.findAll();
+ assertEquals(1, users.size());
+ assertEquals(usr01, users.get(0));
+ assertEquals(1, deletedUsersCount);
+ }
+
+ @Test
+ @Transactional
+ public void givenTwoUsers_whenAddDeletedColumn_ThenUsersHaveDeletedColumn() {
+ User usr01 = new User("usr01", LocalDate.of(2018, 1, 1), "usr01@baeldung.com", 1);
+ usr01.setLastLoginDate(LocalDate.now());
+ User usr02 = new User("usr02", LocalDate.of(2018, 6, 1), "usr02@baeldung.org", 1);
+ usr02.setLastLoginDate(LocalDate.of(2018, 7, 20));
+ usr02.setActive(false);
+
+ userRepository.save(usr01);
+ userRepository.save(usr02);
+
+ userRepository.addDeletedColumn();
+
+ Query nativeQuery = entityManager.createNativeQuery("select deleted from USERS where NAME = 'usr01'");
+ assertEquals(0, nativeQuery.getResultList().get(0));
+ }
+
+ @After
+ public void cleanUp() {
+ userRepository.deleteAll();
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..1b1d264574
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryIntegrationTest.java
@@ -0,0 +1,37 @@
+package com.baeldung.boot.daos;
+
+import com.baeldung.boot.Application;
+import com.baeldung.boot.domain.User;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Created by adam.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+@DirtiesContext
+public class UserRepositoryIntegrationTest extends UserRepositoryCommon {
+
+ @Test
+ @Transactional
+ public void givenUsersInDBWhenUpdateStatusForNameModifyingQueryAnnotationNativeThenModifyMatchingUsers() {
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS));
+ userRepository.flush();
+
+ int updatedUsersSize = userRepository.updateUserSetStatusForNameNative(INACTIVE_STATUS, "SAMPLE");
+
+ assertThat(updatedUsersSize).isEqualTo(2);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java
new file mode 100644
index 0000000000..99eabc8271
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCAutoLiveTest.java
@@ -0,0 +1,43 @@
+package com.baeldung.boot.daos;
+
+import com.baeldung.boot.Application;
+import com.baeldung.boot.domain.User;
+import com.baeldung.util.BaeldungPostgresqlContainer;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+import org.testcontainers.containers.PostgreSQLContainer;
+
+import java.time.LocalDate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Created by adam.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+@ActiveProfiles({"tc", "tc-auto"})
+public class UserRepositoryTCAutoLiveTest extends UserRepositoryCommon {
+
+ @ClassRule
+ public static PostgreSQLContainer postgreSQLContainer = BaeldungPostgresqlContainer.getInstance();
+
+ @Test
+ @Transactional
+ public void givenUsersInDB_WhenUpdateStatusForNameModifyingQueryAnnotationNativePostgres_ThenModifyMatchingUsers() {
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS));
+ userRepository.flush();
+
+ int updatedUsersSize = userRepository.updateUserSetStatusForNameNativePostgres(INACTIVE_STATUS, "SAMPLE");
+
+ assertThat(updatedUsersSize).isEqualTo(2);
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java
new file mode 100644
index 0000000000..be8843c166
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/daos/UserRepositoryTCLiveTest.java
@@ -0,0 +1,58 @@
+package com.baeldung.boot.daos;
+
+import com.baeldung.boot.Application;
+import com.baeldung.boot.domain.User;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.util.TestPropertyValues;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+import org.testcontainers.containers.PostgreSQLContainer;
+
+import java.time.LocalDate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = Application.class)
+@ActiveProfiles("tc")
+@ContextConfiguration(initializers = {UserRepositoryTCLiveTest.Initializer.class})
+public class UserRepositoryTCLiveTest extends UserRepositoryCommon {
+
+ @ClassRule
+ public static PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:11.1")
+ .withDatabaseName("integration-tests-db")
+ .withUsername("sa")
+ .withPassword("sa");
+
+ @Test
+ @Transactional
+ public void givenUsersInDB_WhenUpdateStatusForNameModifyingQueryAnnotationNative_ThenModifyMatchingUsers() {
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE1", LocalDate.now(), USER_EMAIL2, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE", LocalDate.now(), USER_EMAIL3, ACTIVE_STATUS));
+ userRepository.save(new User("SAMPLE3", LocalDate.now(), USER_EMAIL4, ACTIVE_STATUS));
+ userRepository.flush();
+
+ int updatedUsersSize = userRepository.updateUserSetStatusForNameNativePostgres(INACTIVE_STATUS, "SAMPLE");
+
+ assertThat(updatedUsersSize).isEqualTo(2);
+ }
+
+ static class Initializer
+ implements ApplicationContextInitializer {
+ public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
+ TestPropertyValues.of(
+ "spring.datasource.url=" + postgreSQLContainer.getJdbcUrl(),
+ "spring.datasource.username=" + postgreSQLContainer.getUsername(),
+ "spring.datasource.password=" + postgreSQLContainer.getPassword()
+ ).applyTo(configurableApplicationContext.getEnvironment());
+ }
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/AbstractServicePersistenceIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/AbstractServicePersistenceIntegrationTest.java
new file mode 100644
index 0000000000..bf0c85fca6
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/AbstractServicePersistenceIntegrationTest.java
@@ -0,0 +1,252 @@
+package com.baeldung.boot.services;
+
+import com.baeldung.boot.domain.Foo;
+import com.baeldung.boot.services.IOperations;
+import com.baeldung.util.IDUtil;
+import org.hamcrest.Matchers;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.springframework.dao.DataAccessException;
+
+import java.io.Serializable;
+import java.util.List;
+
+import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.*;
+
+public abstract class AbstractServicePersistenceIntegrationTest {
+
+ // tests
+
+ // find - one
+
+ @Test
+ /**/public final void givenResourceDoesNotExist_whenResourceIsRetrieved_thenNoResourceIsReceived() {
+ // When
+ final Foo createdResource = getApi().findOne(IDUtil.randomPositiveLong());
+
+ // Then
+ assertNull(createdResource);
+ }
+
+ @Test
+ public void givenResourceExists_whenResourceIsRetrieved_thenNoExceptions() {
+ final Foo existingResource = persistNewEntity();
+ getApi().findOne(existingResource.getId());
+ }
+
+ @Test
+ public void givenResourceDoesNotExist_whenResourceIsRetrieved_thenNoExceptions() {
+ getApi().findOne(IDUtil.randomPositiveLong());
+ }
+
+ @Test
+ public void givenResourceExists_whenResourceIsRetrieved_thenTheResultIsNotNull() {
+ final Foo existingResource = persistNewEntity();
+ final Foo retrievedResource = getApi().findOne(existingResource.getId());
+ assertNotNull(retrievedResource);
+ }
+
+ @Test
+ public void givenResourceExists_whenResourceIsRetrieved_thenResourceIsRetrievedCorrectly() {
+ final Foo existingResource = persistNewEntity();
+ final Foo retrievedResource = getApi().findOne(existingResource.getId());
+ assertEquals(existingResource, retrievedResource);
+ }
+
+ // find - one - by name
+
+ // find - all
+
+ @Test
+ /**/public void whenAllResourcesAreRetrieved_thenNoExceptions() {
+ getApi().findAll();
+ }
+
+ @Test
+ /**/public void whenAllResourcesAreRetrieved_thenTheResultIsNotNull() {
+ final List resources = getApi().findAll();
+
+ assertNotNull(resources);
+ }
+
+ @Test
+ /**/public void givenAtLeastOneResourceExists_whenAllResourcesAreRetrieved_thenRetrievedResourcesAreNotEmpty() {
+ persistNewEntity();
+
+ // When
+ final List allResources = getApi().findAll();
+
+ // Then
+ assertThat(allResources, not(Matchers. empty()));
+ }
+
+ @Test
+ /**/public void givenAnResourceExists_whenAllResourcesAreRetrieved_thenTheExistingResourceIsIndeedAmongThem() {
+ final Foo existingResource = persistNewEntity();
+
+ final List resources = getApi().findAll();
+
+ assertThat(resources, hasItem(existingResource));
+ }
+
+ @Test
+ /**/public void whenAllResourcesAreRetrieved_thenResourcesHaveIds() {
+ persistNewEntity();
+
+ // When
+ final List allResources = getApi().findAll();
+
+ // Then
+ for (final Foo resource : allResources) {
+ assertNotNull(resource.getId());
+ }
+ }
+
+ // create
+
+ @Test(expected = RuntimeException.class)
+ /**/public void whenNullResourceIsCreated_thenException() {
+ getApi().create(null);
+ }
+
+ @Test
+ /**/public void whenResourceIsCreated_thenNoExceptions() {
+ persistNewEntity();
+ }
+
+ @Test
+ /**/public void whenResourceIsCreated_thenResourceIsRetrievable() {
+ final Foo existingResource = persistNewEntity();
+
+ assertNotNull(getApi().findOne(existingResource.getId()));
+ }
+
+ @Test
+ /**/public void whenResourceIsCreated_thenSavedResourceIsEqualToOriginalResource() {
+ final Foo originalResource = createNewEntity();
+ final Foo savedResource = getApi().create(originalResource);
+
+ assertEquals(originalResource, savedResource);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void whenResourceWithFailedConstraintsIsCreated_thenException() {
+ final Foo invalidResource = createNewEntity();
+ invalidate(invalidResource);
+
+ getApi().create(invalidResource);
+ }
+
+ /**
+ * -- specific to the persistence engine
+ */
+ @Test(expected = DataAccessException.class)
+ @Ignore("Hibernate simply ignores the id silently and still saved (tracking this)")
+ public void whenResourceWithIdIsCreated_thenDataAccessException() {
+ final Foo resourceWithId = createNewEntity();
+ resourceWithId.setId(IDUtil.randomPositiveLong());
+
+ getApi().create(resourceWithId);
+ }
+
+ // update
+
+ @Test(expected = RuntimeException.class)
+ /**/public void whenNullResourceIsUpdated_thenException() {
+ getApi().update(null);
+ }
+
+ @Test
+ /**/public void givenResourceExists_whenResourceIsUpdated_thenNoExceptions() {
+ // Given
+ final Foo existingResource = persistNewEntity();
+
+ // When
+ getApi().update(existingResource);
+ }
+
+ /**
+ * - can also be the ConstraintViolationException which now occurs on the update operation will not be translated; as a consequence, it will be a TransactionSystemException
+ */
+ @Test(expected = RuntimeException.class)
+ public void whenResourceIsUpdatedWithFailedConstraints_thenException() {
+ final Foo existingResource = persistNewEntity();
+ invalidate(existingResource);
+
+ getApi().update(existingResource);
+ }
+
+ @Test
+ /**/public void givenResourceExists_whenResourceIsUpdated_thenUpdatesArePersisted() {
+ // Given
+ final Foo existingResource = persistNewEntity();
+
+ // When
+ change(existingResource);
+ getApi().update(existingResource);
+
+ final Foo updatedResource = getApi().findOne(existingResource.getId());
+
+ // Then
+ assertEquals(existingResource, updatedResource);
+ }
+
+ // delete
+
+ // @Test(expected = RuntimeException.class)
+ // public void givenResourceDoesNotExists_whenResourceIsDeleted_thenException() {
+ // // When
+ // getApi().delete(IDUtil.randomPositiveLong());
+ // }
+ //
+ // @Test(expected = RuntimeException.class)
+ // public void whenResourceIsDeletedByNegativeId_thenException() {
+ // // When
+ // getApi().delete(IDUtil.randomNegativeLong());
+ // }
+ //
+ // @Test
+ // public void givenResourceExists_whenResourceIsDeleted_thenNoExceptions() {
+ // // Given
+ // final Foo existingResource = persistNewEntity();
+ //
+ // // When
+ // getApi().delete(existingResource.getId());
+ // }
+ //
+ // @Test
+ // /**/public final void givenResourceExists_whenResourceIsDeleted_thenResourceNoLongerExists() {
+ // // Given
+ // final Foo existingResource = persistNewEntity();
+ //
+ // // When
+ // getApi().delete(existingResource.getId());
+ //
+ // // Then
+ // assertNull(getApi().findOne(existingResource.getId()));
+ // }
+
+ // template method
+
+ protected Foo createNewEntity() {
+ return new Foo(randomAlphabetic(6));
+ }
+
+ protected abstract IOperations getApi();
+
+ private final void invalidate(final Foo entity) {
+ entity.setName(null);
+ }
+
+ private final void change(final Foo entity) {
+ entity.setName(randomAlphabetic(6));
+ }
+
+ protected Foo persistNewEntity() {
+ return getApi().create(createNewEntity());
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/FooServicePersistenceIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/FooServicePersistenceIntegrationTest.java
new file mode 100644
index 0000000000..72de4918a2
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/FooServicePersistenceIntegrationTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.boot.services;
+
+import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import com.baeldung.boot.Application;
+import com.baeldung.boot.domain.Foo;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes=Application.class)
+public class FooServicePersistenceIntegrationTest extends AbstractServicePersistenceIntegrationTest {
+
+ @Autowired
+ private IFooService service;
+
+ // tests
+
+ @Test
+ public final void whenContextIsBootstrapped_thenNoExceptions() {
+ //
+ }
+
+ @Test
+ public final void whenEntityIsCreated_thenNoExceptions() {
+ service.create(new Foo(randomAlphabetic(6)));
+ }
+
+ @Test(expected = DataIntegrityViolationException.class)
+ public final void whenInvalidEntityIsCreated_thenDataException() {
+ service.create(new Foo());
+ }
+
+ @Test(expected = DataIntegrityViolationException.class)
+ public final void whenEntityWithLongNameIsCreated_thenDataException() {
+ service.create(new Foo(randomAlphabetic(2048)));
+ }
+
+ // custom Query method
+
+ @Test
+ public final void givenUsingCustomQuery_whenRetrievingEntity_thenFound() {
+ final String name = randomAlphabetic(6);
+ service.create(new Foo(name));
+
+ final Foo retrievedByName = service.retrieveByName(name);
+ assertNotNull(retrievedByName);
+ }
+
+ // work in progress
+
+ @Test(expected = InvalidDataAccessApiUsageException.class)
+ @Ignore("Right now, persist has saveOrUpdate semantics, so this will no longer fail")
+ public final void whenSameEntityIsCreatedTwice_thenDataException() {
+ final Foo entity = new Foo(randomAlphabetic(8));
+ service.create(entity);
+ service.create(entity);
+ }
+
+ // API
+
+ @Override
+ protected final IOperations getApi() {
+ return service;
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/SpringDataJPABarAuditIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/SpringDataJPABarAuditIntegrationTest.java
new file mode 100644
index 0000000000..644d1ec805
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/boot/services/SpringDataJPABarAuditIntegrationTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.boot.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import com.baeldung.boot.Application;
+import com.baeldung.boot.domain.Bar;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes=Application.class)
+public class SpringDataJPABarAuditIntegrationTest {
+
+ private static Logger logger = LoggerFactory.getLogger(SpringDataJPABarAuditIntegrationTest.class);
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ logger.info("setUpBeforeClass()");
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ logger.info("tearDownAfterClass()");
+ }
+
+ @Autowired
+ @Qualifier("barSpringDataJpaService")
+ private IBarService barService;
+
+ @Autowired
+ private EntityManagerFactory entityManagerFactory;
+
+ private EntityManager em;
+
+ @Before
+ public void setUp() throws Exception {
+ logger.info("setUp()");
+ em = entityManagerFactory.createEntityManager();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ logger.info("tearDown()");
+ em.close();
+ }
+
+ @Test
+ @WithMockUser(username = "tutorialuser")
+ public final void whenBarsModified_thenBarsAudited() {
+ Bar bar = new Bar("BAR1");
+ barService.create(bar);
+ assertEquals(bar.getCreatedDate(), bar.getModifiedDate());
+ assertEquals("tutorialuser", bar.getCreatedBy(), bar.getModifiedBy());
+ bar.setName("BAR2");
+ bar = barService.update(bar);
+ assertTrue(bar.getCreatedDate() < bar.getModifiedDate());
+ assertEquals("tutorialuser", bar.getCreatedBy(), bar.getModifiedBy());
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/elementcollection/ElementCollectionIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/elementcollection/ElementCollectionIntegrationTest.java
new file mode 100644
index 0000000000..306798aa68
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/elementcollection/ElementCollectionIntegrationTest.java
@@ -0,0 +1,64 @@
+package com.baeldung.elementcollection;
+
+import com.baeldung.elementcollection.model.Employee;
+import com.baeldung.elementcollection.model.Phone;
+import com.baeldung.elementcollection.repository.EmployeeRepository;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = ElementCollectionApplication.class)
+public class ElementCollectionIntegrationTest {
+
+ @Autowired
+ private EmployeeRepository employeeRepository;
+
+ @Before
+ public void init() {
+ Employee employee = new Employee(1, "Fred");
+ employee.setPhones(
+ Arrays.asList(new Phone("work", "+55", "99999-9999"), new Phone("home", "+55", "98888-8888")));
+ employeeRepository.save(employee);
+ }
+
+ @After
+ public void clean() {
+ employeeRepository.remove(1);
+ }
+
+ @Test(expected = org.hibernate.LazyInitializationException.class)
+ public void whenAccessLazyCollection_thenThrowLazyInitializationException() {
+ Employee employee = employeeRepository.findById(1);
+ assertThat(employee.getPhones().size(), is(2));
+ }
+
+ @Test
+ public void whenUseJPAQL_thenFetchResult() {
+ Employee employee = employeeRepository.findByJPQL(1);
+ assertThat(employee.getPhones().size(), is(2));
+ }
+
+ @Test
+ public void whenUseEntityGraph_thenFetchResult() {
+ Employee employee = employeeRepository.findByEntityGraph(1);
+ assertThat(employee.getPhones().size(), is(2));
+ }
+
+ @Test
+ @Transactional
+ public void whenUseTransaction_thenFetchResult() {
+ Employee employee = employeeRepository.findById(1);
+ assertThat(employee.getPhones().size(), is(2));
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java
new file mode 100644
index 0000000000..a1f4a3fa2c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/JpaMultipleDBIntegrationTest.java
@@ -0,0 +1,96 @@
+package com.baeldung.multipledb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.multipledb.dao.product.ProductRepository;
+import com.baeldung.multipledb.dao.user.PossessionRepository;
+import com.baeldung.multipledb.dao.user.UserRepository;
+import com.baeldung.multipledb.model.product.Product;
+import com.baeldung.multipledb.model.user.PossessionMultipleDB;
+import com.baeldung.multipledb.model.user.UserMultipleDB;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes=MultipleDbApplication.class)
+@EnableTransactionManagement
+public class JpaMultipleDBIntegrationTest {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private PossessionRepository possessionRepository;
+
+ @Autowired
+ private ProductRepository productRepository;
+
+ // tests
+
+ @Test
+ @Transactional("userTransactionManager")
+ public void whenCreatingUser_thenCreated() {
+ UserMultipleDB user = new UserMultipleDB();
+ user.setName("John");
+ user.setEmail("john@test.com");
+ user.setAge(20);
+ PossessionMultipleDB p = new PossessionMultipleDB("sample");
+ p = possessionRepository.save(p);
+ user.setPossessionList(Collections.singletonList(p));
+ user = userRepository.save(user);
+ final Optional result = userRepository.findById(user.getId());
+ assertTrue(result.isPresent());
+ System.out.println(result.get().getPossessionList());
+ assertEquals(1, result.get().getPossessionList().size());
+ }
+
+ @Test
+ @Transactional("userTransactionManager")
+ public void whenCreatingUsersWithSameEmail_thenRollback() {
+ UserMultipleDB user1 = new UserMultipleDB();
+ user1.setName("John");
+ user1.setEmail("john@test.com");
+ user1.setAge(20);
+ user1 = userRepository.save(user1);
+ assertTrue(userRepository.findById(user1.getId()).isPresent());
+
+ UserMultipleDB user2 = new UserMultipleDB();
+ user2.setName("Tom");
+ user2.setEmail("john@test.com");
+ user2.setAge(10);
+ try {
+ user2 = userRepository.save(user2);
+ userRepository.flush();
+ fail("DataIntegrityViolationException should be thrown!");
+ } catch (final DataIntegrityViolationException e) {
+ // Expected
+ } catch (final Exception e) {
+ fail("DataIntegrityViolationException should be thrown, instead got: " + e);
+ }
+ }
+
+ @Test
+ @Transactional("productTransactionManager")
+ public void whenCreatingProduct_thenCreated() {
+ Product product = new Product();
+ product.setName("Book");
+ product.setId(2);
+ product.setPrice(20);
+ product = productRepository.save(product);
+
+ assertTrue(productRepository.findById(product.getId()).isPresent());
+ }
+
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java
new file mode 100644
index 0000000000..9bfba61a3b
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/multipledb/ProductRepositoryIntegrationTest.java
@@ -0,0 +1,144 @@
+package com.baeldung.multipledb;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+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.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.baeldung.multipledb.PersistenceProductConfiguration;
+import com.baeldung.multipledb.dao.product.ProductRepository;
+import com.baeldung.multipledb.model.product.Product;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes=MultipleDbApplication.class)
+@EnableTransactionManagement
+public class ProductRepositoryIntegrationTest {
+
+ @Autowired
+ private ProductRepository productRepository;
+
+ @Before
+ @Transactional("productTransactionManager")
+ public void setUp() {
+ productRepository.save(Product.from(1001, "Book", 21));
+ productRepository.save(Product.from(1002, "Coffee", 10));
+ productRepository.save(Product.from(1003, "Jeans", 30));
+ productRepository.save(Product.from(1004, "Shirt", 32));
+ productRepository.save(Product.from(1005, "Bacon", 10));
+ }
+
+ @Test
+ public void whenRequestingFirstPageOfSizeTwo_ThenReturnFirstPage() {
+ Pageable pageRequest = PageRequest.of(0, 2);
+
+ Page result = productRepository.findAll(pageRequest);
+
+ assertThat(result.getContent(), hasSize(2));
+ assertTrue(result.stream()
+ .map(Product::getId)
+ .allMatch(id -> Arrays.asList(1001, 1002)
+ .contains(id)));
+ }
+
+ @Test
+ public void whenRequestingSecondPageOfSizeTwo_ThenReturnSecondPage() {
+ Pageable pageRequest = PageRequest.of(1, 2);
+
+ Page result = productRepository.findAll(pageRequest);
+
+ assertThat(result.getContent(), hasSize(2));
+ assertTrue(result.stream()
+ .map(Product::getId)
+ .allMatch(id -> Arrays.asList(1003, 1004)
+ .contains(id)));
+ }
+
+ @Test
+ public void whenRequestingLastPage_ThenReturnLastPageWithRemData() {
+ Pageable pageRequest = PageRequest.of(2, 2);
+
+ Page result = productRepository.findAll(pageRequest);
+
+ assertThat(result.getContent(), hasSize(1));
+ assertTrue(result.stream()
+ .map(Product::getId)
+ .allMatch(id -> Arrays.asList(1005)
+ .contains(id)));
+ }
+
+ @Test
+ public void whenSortingByNameAscAndPaging_ThenReturnSortedPagedResult() {
+ Pageable pageRequest = PageRequest.of(0, 3, Sort.by("name"));
+
+ Page result = productRepository.findAll(pageRequest);
+
+ assertThat(result.getContent(), hasSize(3));
+ assertThat(result.getContent()
+ .stream()
+ .map(Product::getId)
+ .collect(Collectors.toList()), equalTo(Arrays.asList(1005, 1001, 1002)));
+
+ }
+
+ @Test
+ public void whenSortingByPriceDescAndPaging_ThenReturnSortedPagedResult() {
+ Pageable pageRequest = PageRequest.of(0, 3, Sort.by("price")
+ .descending());
+
+ Page result = productRepository.findAll(pageRequest);
+
+ assertThat(result.getContent(), hasSize(3));
+ assertThat(result.getContent()
+ .stream()
+ .map(Product::getId)
+ .collect(Collectors.toList()), equalTo(Arrays.asList(1004, 1003, 1001)));
+
+ }
+
+ @Test
+ public void whenSortingByPriceDescAndNameAscAndPaging_ThenReturnSortedPagedResult() {
+ Pageable pageRequest = PageRequest.of(0, 5, Sort.by("price")
+ .descending()
+ .and(Sort.by("name")));
+
+ Page result = productRepository.findAll(pageRequest);
+
+ assertThat(result.getContent(), hasSize(5));
+ assertThat(result.getContent()
+ .stream()
+ .map(Product::getId)
+ .collect(Collectors.toList()), equalTo(Arrays.asList(1004, 1003, 1001, 1005, 1002)));
+
+ }
+
+ @Test
+ public void whenRequestingFirstPageOfSizeTwoUsingCustomMethod_ThenReturnFirstPage() {
+ Pageable pageRequest = PageRequest.of(0, 2);
+
+ List result = productRepository.findAllByPrice(10, pageRequest);
+
+ assertThat(result, hasSize(2));
+ assertTrue(result.stream()
+ .map(Product::getId)
+ .allMatch(id -> Arrays.asList(1002, 1005)
+ .contains(id)));
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..71a4dbda3f
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,81 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-lower-case-naming-strategy.properties")
+class QuotedLowerCaseNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenException(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..6b1c984600
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedLowerCaseNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-lower-case-naming-strategy-on-postgres.properties")
+class QuotedLowerCaseNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..f819327a5c
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-upper-case-naming-strategy.properties")
+class QuotedUpperCaseNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonUnquoted_thenException(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..bd23b81b4b
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/QuotedUpperCaseNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,81 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("quoted-upper-case-naming-strategy-on-postgres.properties")
+class QuotedUpperCaseNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndUpperCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..1850fea173
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("spring-physical-naming-strategy.properties")
+class SpringPhysicalNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedUpperCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Unexpected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedLowerCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..e26ebb148d
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/SpringPhysicalNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("spring-physical-naming-strategy-on-postgres.properties")
+class SpringPhysicalNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndSpringNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyH2IntegrationTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyH2IntegrationTest.java
new file mode 100644
index 0000000000..6311c42e93
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyH2IntegrationTest.java
@@ -0,0 +1,86 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("unquoted-lower-case-naming-strategy.properties")
+class UnquotedLowerCaseNamingStrategyH2IntegrationTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Unexpected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Unexpected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ public Person fromDatabase(Object databaseRow) {
+ Object[] typedDatabaseRow = (Object[]) databaseRow;
+
+ return new Person(
+ ((BigInteger) typedDatabaseRow[0]).longValue(),
+ (String) typedDatabaseRow[1],
+ (String) typedDatabaseRow[2]
+ );
+ }
+}
diff --git a/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyPostgresLiveTest.java b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyPostgresLiveTest.java
new file mode 100644
index 0000000000..033a213cf5
--- /dev/null
+++ b/persistence-modules/spring-data-jpa-enterprise/src/test/java/com/baeldung/namingstrategy/UnquotedLowerCaseNamingStrategyPostgresLiveTest.java
@@ -0,0 +1,85 @@
+package com.baeldung.namingstrategy;
+
+import org.hibernate.exception.SQLGrammarException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+import org.springframework.test.context.TestPropertySource;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DataJpaTest(excludeAutoConfiguration = TestDatabaseAutoConfiguration.class)
+@TestPropertySource("unquoted-lower-case-naming-strategy-on-postgres.properties")
+class UnquotedLowerCaseNamingStrategyPostgresLiveTest {
+
+ @PersistenceContext
+ private EntityManager entityManager;
+
+ @Autowired
+ private PersonRepository personRepository;
+
+ @BeforeEach
+ void insertPeople() {
+ personRepository.saveAll(Arrays.asList(
+ new Person(1L, "John", "Doe"),
+ new Person(2L, "Jane", "Doe"),
+ new Person(3L, "Ted", "Mosby")
+ ));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"person", "PERSON", "Person"})
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonUnquoted_thenResult(String tableName) {
+ Query query = entityManager.createNativeQuery("select * from " + tableName);
+
+ // Expected result
+ List result = (List) query.getResultStream()
+ .map(this::fromDatabase)
+ .collect(Collectors.toList());
+
+ assertThat(result).isNotEmpty();
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedUpperCase_thenException() {
+ Query query = entityManager.createNativeQuery("select * from \"PERSON\"");
+
+ // Expected result
+ assertThrows(SQLGrammarException.class, query::getResultStream);
+ }
+
+ @Test
+ void givenPeopleAndLowerCaseNamingStrategy_whenQueryPersonQuotedLowerCase_thenResult() {
+ Query query = entityManager.createNativeQuery("select * from \"person\"");
+
+ // Expected result
+ List