This commit is contained in:
ICKostiantyn.Ivanov
2024-04-14 18:14:42 +02:00
834 changed files with 12312 additions and 3282 deletions
+42
View File
@@ -0,0 +1,42 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<artifactId>duckdb</artifactId>
<name>duckdb</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>9</source>
<target>9</target>
</configuration>
</plugin>
</plugins>
</build>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>persistence-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<duckdb.version>0.10.0</duckdb.version>
</properties>
<dependencies>
<dependency>
<groupId>org.duckdb</groupId>
<artifactId>duckdb_jdbc</artifactId>
<version>${duckdb.version}</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,198 @@
package com.baeldung;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
class DuckDbAccessIntegrationTest {
private Connection conn = null;
private Statement stmt = null;
@BeforeAll
static void setupOnce() throws Exception {
Class.forName("org.duckdb.DuckDBDriver");
}
@BeforeEach
void setup() throws SQLException {
conn = DriverManager.getConnection("jdbc:duckdb:");
stmt = conn.createStatement();
}
@Test
void whenQueryCurrentDate_thenReturnToday() throws SQLException {
ResultSet rs = stmt.executeQuery("SELECT current_date");
Date currentDate = rs.next() ? rs.getDate(1) : null;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date expectedDate = calendar.getTime();
assertThat(currentDate).isEqualTo(expectedDate);
}
@Test
void whenReadCsv_thenReturnHeaderAndData() throws SQLException {
String filePath = getResourceAbsolutePath("/customer.csv");
String query = String.format("SELECT * FROM read_csv('%s')", filePath);
ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData metadata = rs.getMetaData();
List<String> actualHeaderNames = new ArrayList<>();
for (int n=1; n<=metadata.getColumnCount(); n++) {
actualHeaderNames.add(metadata.getColumnLabel(n));
}
// Then
List<String> expectedHeaderNames = List.of("CustomerId", "FirstName", "LastName", "Gender");
assertThat(actualHeaderNames).isEqualTo(expectedHeaderNames);
int rowCount = 0;
while (rs.next()) {
rowCount++;
}
assertThat(rowCount).isEqualTo(10);
}
@Test
void whenImportByCsv_thenReturnCorrectRowCount() throws SQLException {
// When
String filePath = getResourceAbsolutePath("/customer.csv");
String query = String.format("CREATE TABLE customer AS SELECT * FROM read_csv('%s')", filePath);
stmt.executeUpdate(query);
// Then
assertThat(getTableRowCount(conn, "customer")).isEqualTo(10);
}
@Test
void whenImportByJson_thenReturnCorrectRowCount() throws SQLException {
// When
String filePath = getResourceAbsolutePath("/product.json");
String query = String.format("CREATE TABLE product AS SELECT * FROM read_json('%s')", filePath);
stmt.executeUpdate(query);
// Then
assertThat(getTableRowCount(conn, "product")).isEqualTo(3);
}
@Test
void whenImportByInsert_thenReturnCorrectRowCount() throws SQLException {
// When
stmt.executeUpdate("CREATE TABLE purchase(customerId BIGINT, productId BIGINT)");
String query = "INSERT INTO purchase(customerId, productId) VALUES (?,?)";
try (PreparedStatement pStmt = conn.prepareStatement(query)) {
pStmt.setInt(1, 101);
pStmt.setInt(2, 1);
pStmt.addBatch();
pStmt.setInt(1, 101);
pStmt.setInt(2, 2);
pStmt.addBatch();
pStmt.setInt(1, 102);
pStmt.setInt(2, 2);
pStmt.addBatch();
pStmt.executeBatch();
}
// Then
assertThat(getTableRowCount(conn, "purchase")).isEqualTo(3);
}
@Test
void whenQueryWithJoin_thenReturnCorrectCount() throws SQLException {
String customerFilePath = getResourceAbsolutePath("/customer.csv");
String productFilePath = getResourceAbsolutePath("/product.json");
whenImportByInsert_thenReturnCorrectRowCount();
String query = String.format("SELECT C.firstName, C.lastName, P.productName " +
"FROM read_csv('%s') AS C, read_json('%s') AS P, purchase S " +
"WHERE S.customerId = C.customerId " +
"AND S.productId = P.productId ",
customerFilePath, productFilePath);
int count = 0;
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
count++;
}
assertThat(count).isEqualTo(3);
}
@Test
void whenExportData_thenFileIsCreated() throws IOException, SQLException {
createPurchaseView(conn);
File tempFile = File.createTempFile("temp", "");
String exportFilePath = tempFile.getAbsolutePath();
String query = String.format("COPY purchase_view TO '%s'", exportFilePath);
stmt.executeUpdate(query);
assertThat(tempFile.length()).isGreaterThan(0);
tempFile.delete();
}
@AfterEach
void tearDown() throws SQLException {
stmt.close();
conn.close();
}
private String getResourceAbsolutePath(String name) {
return this.getClass().getResource(name).getPath().replaceFirst("/", "");
}
private int getTableRowCount(Connection conn, String tableName) throws SQLException {
try (Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery(String.format("SELECT COUNT(*) FROM %s", tableName));
return (rs.next()) ? rs.getInt(1) : 0;
}
}
private void createPurchaseView(Connection conn) throws SQLException {
whenImportByCsv_thenReturnCorrectRowCount();
whenImportByJson_thenReturnCorrectRowCount();
whenImportByInsert_thenReturnCorrectRowCount();
String query = "CREATE VIEW purchase_view AS " +
"SELECT P.productName, COUNT(*) AS purchaseCount " +
"FROM customer C, product P, purchase S " +
"WHERE S.customerId = C.customerId " +
"AND S.productId = P.productId " +
"GROUP BY P.productName " +
"ORDER BY COUNT(*) DESC ";
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate(query);
}
}
}
@@ -0,0 +1,11 @@
CustomerId,FirstName,LastName,Gender
101,John,Smith,Male
102,Sarah,Jones,Female
103,Michael,Johnson,Male
104,Emily,Davis,Female
105,David,Brown,Male
106,Emma,Williams,Female
107,Alexander,Miller,Male
108,Samantha,Anderson,Female
109,Matthew,Taylor,Male
110,Olivia,Thompson,Female
1 CustomerId FirstName LastName Gender
2 101 John Smith Male
3 102 Sarah Jones Female
4 103 Michael Johnson Male
5 104 Emily Davis Female
6 105 David Brown Male
7 106 Emma Williams Female
8 107 Alexander Miller Male
9 108 Samantha Anderson Female
10 109 Matthew Taylor Male
11 110 Olivia Thompson Female
@@ -0,0 +1,17 @@
[
{
"productId": 1,
"productName":"EZ Curl Bar",
"category": "Sports Equipment"
},
{
"productId": 2,
"productName": "7' Barbell",
"category": "Sports Equipment"
},
{
"productId": 3,
"productName": "Single Mouthguard - Black",
"category": "Sports Equipment"
}
]
@@ -0,0 +1,6 @@
## Hibernate Annotations
This module contains articles about Annotations used in Hibernate.
### Relevant Articles:
- [@Subselect Annotation in Hibernate](https://www.baeldung.com/hibernate-subselect)
@@ -0,0 +1,109 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>hibernate-annotations-2</artifactId>
<version>0.1-SNAPSHOT</version>
<name>hibernate-annotations-2</name>
<packaging>jar</packaging>
<description>Hibernate annotations module, part 2</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>persistence-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>${org.springframework.data.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-core.version}</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-testing</artifactId>
<version>${hibernate-core.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>${hibernate-core.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>${tomcat-dbcp.version}</version>
</dependency>
<!-- validation -->
<!-- utils -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.hypersistence</groupId>
<artifactId>hypersistence-utils-hibernate-60</artifactId>
<version>${hypersistance-utils-hibernate-60.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase-core.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<properties>
<!-- Spring -->
<org.springframework.version>6.0.6</org.springframework.version>
<org.springframework.data.version>3.0.3</org.springframework.data.version>
<hibernate-core.version>6.4.2.Final</hibernate-core.version>
<maven.deploy.skip>true</maven.deploy.skip>
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
<hypersistance-utils-hibernate-60.version>3.3.1</hypersistance-utils-hibernate-60.version>
<lombok.version>1.18.30</lombok.version>
<liquibase-core.version>4.24.0</liquibase-core.version>
</properties>
</project>
@@ -0,0 +1,50 @@
package com.baeldung.hibernate;
import com.baeldung.hibernate.subselect.RuntimeConfiguration;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;
import org.hibernate.service.ServiceRegistry;
public class HibernateAnnotationUtil {
private static final SessionFactory SESSION_FACTORY = buildSessionFactory();
/**
* Utility class
*/
private HibernateAnnotationUtil() {
}
public static SessionFactory getSessionFactory() {
return SESSION_FACTORY;
}
private static SessionFactory buildSessionFactory() {
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(dbSettings())
.build();
Metadata metadata = new MetadataSources(serviceRegistry)
.addAnnotatedClass(RuntimeConfiguration.class)
.buildMetadata();
return metadata.buildSessionFactory();
}
private static Map<String, Object> dbSettings() {
Map<String, Object> dbSettings = new HashMap<>();
dbSettings.put(Environment.URL, "jdbc:h2:mem:spring_hibernate_one_to_many");
dbSettings.put(Environment.USER, "sa");
dbSettings.put(Environment.PASS, "");
dbSettings.put(Environment.DRIVER, "org.h2.Driver");
dbSettings.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
dbSettings.put(Environment.SHOW_SQL, "true");
dbSettings.put(Environment.HBM2DDL_AUTO, "create");
return dbSettings;
}
}
@@ -0,0 +1,67 @@
package com.baeldung.hibernate;
import com.google.common.base.Preconditions;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:persistence-h2.properties" })
public class PersistenceConfig {
@Autowired
private Environment env;
@Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.baeldung.hibernate" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
public DataSource dataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
@Bean
public PlatformTransactionManager hibernateTransactionManager() {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", "false");
return hibernateProperties;
}
}
@@ -0,0 +1,43 @@
package com.baeldung.hibernate.subselect;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import java.time.Instant;
import lombok.Data;
import lombok.experimental.Accessors;
import org.hibernate.annotations.Subselect;
@Data
@Accessors(chain = true)
@Entity
// language=sql
@Subselect(value =
"SELECT\n"
+ " ss.id,\n"
+ " ss.attr_key,\n"
+ " ss.val,\n"
+ " ss.created_at\n"
+ " FROM system_settings AS ss\n"
+ " INNER JOIN (\n"
+ " SELECT\n"
+ " ss2.attr_key as k2,\n"
+ " MAX(ss2.created_at) as ca2\n"
+ " FROM system_settings ss2\n"
+ " GROUP BY ss2.attr_key\n"
+ " ) AS t ON t.k2 = ss.attr_key AND t.ca2 = ss.created_at\n"
+ " WHERE ss.type = 'SYSTEM' AND ss.active IS TRUE\n")
public class RuntimeConfiguration {
@Id
private Long id;
@Column(name = "attr_key")
private String key;
@Column(name = "val")
private String value;
@Column(name = "created_at")
private Instant createdAt;
}
@@ -0,0 +1,55 @@
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
<changeSet id="4" author="Mikhail Polivakha">
<createTable tableName="system_settings">
<column name="id" type="bigserial" autoIncrement="true">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="attr_key" type="text">
<constraints nullable="false"/>
</column>
<column name="val" type="text">
<constraints nullable="false"/>
</column>
<column name="type" type="text">
<constraints nullable="false"/>
</column>
<column name="active" type="boolean">
<constraints nullable="false"/>
</column>
<column name="created_at" type="timestamptz">
<constraints nullable="false"/>
</column>
</createTable>
<insert tableName="system_settings">
<column name="id">1</column>
<column name="attr_key">splitting.enabled</column>
<column name="val">true</column>
<column name="active">true</column>
<column name="type">SYSTEM</column>
<column name="created_at" valueComputed="NOW()"/>
</insert>
<insert tableName="system_settings">
<column name="id">2</column>
<column name="attr_key">splitting.enabled</column>
<column name="val">false</column>
<column name="active">false</column>
<column name="type">SYSTEM</column>
<column name="created_at" valueComputed="NOW()"/>
</insert>
<insert tableName="system_settings">
<column name="id">3</column>
<column name="attr_key">redelivery.enabled</column>
<column name="val">false</column>
<column name="active">true</column>
<column name="type">ORDER</column>
<column name="created_at" valueComputed="NOW()"/>
</insert>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,7 @@
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.4.xsd">
<include file="V1__init.xml" relativeToChangelogFile="true" />
</databaseChangeLog>
@@ -0,0 +1,15 @@
# jdbc.X
jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
jdbc.eventGeneratedId=sa
jdbc.user=sa
jdbc.pass=
# hibernate.X
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create-drop
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=true
hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
@@ -0,0 +1,18 @@
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
import com.baeldung.hibernate.PersistenceConfig;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class)
public class SpringContextTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,65 @@
package com.baeldung.hibernate.subselect;
import com.baeldung.hibernate.HibernateAnnotationUtil;
import jakarta.persistence.criteria.Root;
import liquibase.Contexts;
import liquibase.LabelExpression;
import liquibase.Liquibase;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.hibernate.Session;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class SubselectIntegrationTest {
@BeforeAll
static void setUp() {
Session currentSession = HibernateAnnotationUtil.getSessionFactory().getCurrentSession();
currentSession.beginTransaction();
currentSession.doWork(it -> {
Liquibase liquibase;
try {
liquibase = new Liquibase(
"migrations/master.xml",
new ClassLoaderResourceAccessor(),
DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(it))
);
liquibase.update(new Contexts(), new LabelExpression(),true);
} catch (LiquibaseException e) {
throw new RuntimeException(e);
}
});
currentSession.getTransaction().commit();
}
@Test
void givenEntityMarkedWithSubselect_whenSelectingRuntimeConfigByKey_thenSelectedSuccessfully() {
String key = "splitting.enabled";
Session entityManager = HibernateAnnotationUtil.getSessionFactory().getCurrentSession();
entityManager.beginTransaction();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<RuntimeConfiguration> query = criteriaBuilder.createQuery(RuntimeConfiguration.class);
Root<RuntimeConfiguration> root = query.from(RuntimeConfiguration.class);
RuntimeConfiguration configurationParameter = entityManager.createQuery(
query.select(root).where(criteriaBuilder.equal(root.get("key"), key))
).getSingleResult();
entityManager.getTransaction().commit();
Assertions.assertThat(configurationParameter.getValue()).isEqualTo("true");
}
}
@@ -13,3 +13,4 @@ This module contains articles about Annotations used in Hibernate.
- [Hibernate @CreationTimestamp and @UpdateTimestamp](https://www.baeldung.com/hibernate-creationtimestamp-updatetimestamp)
- [Difference Between @JoinColumn and @PrimaryKeyJoinColumn in JPA](https://www.baeldung.com/java-jpa-join-vs-primarykeyjoin)
- [A Guide to the @SoftDelete Annotation in Hibernate](https://www.baeldung.com/java-hibernate-softdelete-annotation)
- [@Subselect Annotation in Hibernate](https://www.baeldung.com/hibernate-subselect)
@@ -81,6 +81,16 @@
<artifactId>hypersistence-utils-hibernate-60</artifactId>
<version>${hypersistance-utils-hibernate-60.version}</version>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase-core.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
<properties>
@@ -91,6 +101,8 @@
<maven.deploy.skip>true</maven.deploy.skip>
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
<hypersistance-utils-hibernate-60.version>3.3.1</hypersistance-utils-hibernate-60.version>
<lombok.version>1.18.30</lombok.version>
<liquibase-core.version>4.24.0</liquibase-core.version>
</properties>
</project>
+2 -1
View File
@@ -13,4 +13,5 @@ This module contains articles specific to use of Hibernate as a JPA implementati
- [Enabling Transaction Locks in Spring Data JPA](https://www.baeldung.com/java-jpa-transaction-locks)
- [JPA/Hibernate Persistence Context](https://www.baeldung.com/jpa-hibernate-persistence-context)
- [Quick Guide to EntityManager#getReference()](https://www.baeldung.com/jpa-entity-manager-get-reference)
- [JPA Entities and the Serializable Interface](https://www.baeldung.com/jpa-entities-serializable)
- [JPA Entities and the Serializable Interface](https://www.baeldung.com/jpa-entities-serializable)
- [The @Struct Annotation Type in Hibernate Structured User-Defined Types](https://www.baeldung.com/java-hibernate-struct-annotation)
@@ -0,0 +1,51 @@
package com.baeldung.hibernate.struct.entities;
import jakarta.persistence.*;
@Entity
public class StructDepartment {
@Id
@GeneratedValue
private Integer id;
@Column
private String departmentName;
@Embedded
@Column
private StructManager manager;
@Override
public String toString() {
return "Department{" +
"id=" + id +
", departmentName='" + departmentName + '\'' +
", manager=" + manager +
'}';
}
public StructDepartment(String departmentName, StructManager manager) {
this.departmentName = departmentName;
this.manager = manager;
}
public Integer getId() {
return id;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public StructManager getManager() {
return manager;
}
public void setManager(StructManager manager) {
this.manager = manager;
}
}
@@ -0,0 +1,52 @@
package com.baeldung.hibernate.struct.entities;
import jakarta.persistence.Embeddable;
import org.hibernate.annotations.Struct;
import java.io.Serializable;
@Embeddable
@Struct(name = "Department_Manager_Type", attributes = {"firstName", "lastName", "qualification"})
public class StructManager implements Serializable {
private String firstName;
private String lastName;
private String qualification;
@Override
public String toString() {
return "Manager{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", qualification='" + qualification + '\'' +
'}';
}
public StructManager(String firstName, String lastName, String qualification) {
this.firstName = firstName;
this.lastName = lastName;
this.qualification = qualification;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getQualification() {
return qualification;
}
public void setQualification(String qualification) {
this.qualification = qualification;
}
}
@@ -0,0 +1,101 @@
package com.baeldung.hibernate.struct;
import com.baeldung.hibernate.struct.entities.StructDepartment;
import com.baeldung.hibernate.struct.entities.StructManager;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
public class HibernateStructUnitTest {
private Session session;
private Transaction transaction;
public static SessionFactory getSessionFactoryByProperties(Properties properties) throws IOException {
ServiceRegistry serviceRegistry = configureServiceRegistry(properties);
return makeSessionFactory(serviceRegistry);
}
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addPackage("com.baeldung.hibernate.struct.entities");
metadataSources.addAnnotatedClass(StructDepartment.class);
metadataSources.addAnnotatedClass(StructManager.class);
Metadata metadata = metadataSources.getMetadataBuilder()
.build();
return metadata.getSessionFactoryBuilder()
.build();
}
private static ServiceRegistry configureServiceRegistry(Properties properties) throws IOException {
return new StandardServiceRegistryBuilder().applySettings(properties)
.build();
}
public static Properties getProperties() throws IOException {
Properties properties = new Properties();
URL propertiesURL = Thread.currentThread()
.getContextClassLoader()
.getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, "hibernate-derby.properties"));
try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
properties.load(inputStream);
}
return properties;
}
private static ServiceRegistry configureServiceRegistry() throws IOException {
return configureServiceRegistry(getProperties());
}
private static String PROPERTY_FILE_NAME;
public static SessionFactory getSessionFactory(String propertyFileName) throws IOException {
PROPERTY_FILE_NAME = propertyFileName;
ServiceRegistry serviceRegistry = configureServiceRegistry();
return makeSessionFactory(serviceRegistry);
}
@Before
public void setUp() throws IOException {
session = getSessionFactory("hibernate-derby.properties")
.openSession();
transaction = session.beginTransaction();
transaction.commit();
transaction = session.beginTransaction();
}
@After
public void tearDown() {
transaction.rollback();
session.close();
}
/* This unit test is for reference only because the Hibernate dialect for
Apache Derby database does not support @Struct annotation.
@Test
public void givenSaveDepartmentObject_ThenManagerUDTExists() {
StructDepartment d = new StructDepartment("Information Technology"
, new StructManager("Zeeshan", "Arif", "Qualified"));
session.persist(d);
session.flush();
session.clear();
}*/
}
@@ -0,0 +1,17 @@
hibernate.connection.driver_class=org.apache.derby.jdbc.EmbeddedDriver
hibernate.connection.url=jdbc:derby:db/derby.dbfile;create=true
hibernate.connection.username=
hibernate.connection.autocommit=true
jdbc.password=
hibernate.dialect=org.hibernate.dialect.DerbyDialect
# enable to see Hibernate generated SQL
hibernate.show_sql=false
hibernate.hbm2ddl.auto=create-drop
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.acquire_increment=5
hibernate.c3p0.timeout=1800
@@ -13,3 +13,4 @@ This module contains articles about use of Queries in Hibernate.
- [Distinct Queries in HQL](https://www.baeldung.com/java-hql-distinct)
- [JPA and Hibernate Criteria vs. JPQL vs. HQL Query](https://www.baeldung.com/jpql-hql-criteria-query)
- [Database Keywords as Columns in Hibernate Entities](https://www.baeldung.com/java-hibernate-db-keywords-as-columns)
- [Get List of Entity From Database in Hibernate](https://www.baeldung.com/java-hibernate-fetch-entity-list)
@@ -0,0 +1,40 @@
package com.baeldung.hibernate.listentity.entity;
import java.util.List;
import jakarta.persistence.*;
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "department", fetch = FetchType.EAGER)
private List<Employee> employees;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Employee> getEmployees() {
return employees;
}
public void setEmployees(List<Employee> employees) {
this.employees = employees;
}
}
@@ -0,0 +1,41 @@
package com.baeldung.hibernate.listentity.entity;
import jakarta.persistence.*;
@Entity
@NamedQuery(name = "findAllEmployees", query = "SELECT e FROM Employee e")
@NamedQuery(name = "findEmployeesByDepartment", query = "SELECT e FROM Employee e WHERE e.department = :department ORDER BY e.lastName ASC")
public class Employee {
@Id
@GeneratedValue
private Long id;
private String lastName;
private String department;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
@@ -0,0 +1,88 @@
package com.baeldung.hibernate.listentity.service;
import java.util.Collections;
import java.util.List;
import jakarta.persistence.*;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.stereotype.Service;
import com.baeldung.hibernate.listentity.entity.Department;
import com.baeldung.hibernate.listentity.entity.Employee;
@Service
public class EmployeeService {
@PersistenceContext
private EntityManager entityManager;
public List<Employee> getAllEmployeesUsingJPQL() {
String jpqlQuery = "SELECT e FROM Employee e";
Query query = entityManager.createQuery(jpqlQuery, Employee.class);
return query.getResultList();
}
public List<Employee> getAllEmployeesByDepartmentUsingJPQL() {
String jpqlQuery = "SELECT e FROM Employee e WHERE e.department = 'Engineering' ORDER BY e.lastName ASC";
Query query = entityManager.createQuery(jpqlQuery, Employee.class);
return query.getResultList();
}
public List<Employee> getAllEmployeesUsingNamedQuery() {
Query query = entityManager.createNamedQuery("findAllEmployees", Employee.class);
return query.getResultList();
}
public List<Employee> getAllEmployeesByDepartmentUsingNamedQuery(String department) {
Query query = entityManager.createNamedQuery("findEmployeesByDepartment", Employee.class);
query.setParameter("department", department);
return query.getResultList();
}
public List<Employee> getAllEmployeesUsingCriteriaAPI() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> employeeRoot = criteriaQuery.from(Employee.class);
criteriaQuery.select(employeeRoot);
Query query = entityManager.createQuery(criteriaQuery);
return query.getResultList();
}
public List<Employee> getAllEmployeesByDepartmentUsingCriteriaAPI(String department) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> employeeRoot = criteriaQuery.from(Employee.class);
Predicate departmentPredicate = criteriaBuilder.equal(employeeRoot.get("department"), department);
Path<Object> sortByPath = employeeRoot.get("lastName");
criteriaQuery.orderBy(criteriaBuilder.asc(sortByPath));
criteriaQuery.select(employeeRoot)
.where(departmentPredicate);
Query query = entityManager.createQuery(criteriaQuery);
return query.getResultList();
}
public List<Employee> getAllEmployeesByDepartmentUsingOneToManyAnnotations(String departmentName) {
try {
// Retrieve the department by its name
Department department = entityManager.createQuery("SELECT d FROM Department d WHERE d.name = :name", Department.class)
.setParameter("name", departmentName)
.getSingleResult();
// Return the list of employees associated with the department
return department.getEmployees();
} catch (NoResultException e) {
return Collections.emptyList();
}
}
}
@@ -0,0 +1,56 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables;
import com.baeldung.jooq.jointables.public_.Public;
import java.util.Arrays;
import java.util.List;
import org.jooq.Constants;
import org.jooq.Schema;
import org.jooq.impl.CatalogImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class DefaultCatalog extends CatalogImpl {
private static final long serialVersionUID = 1L;
/**
* The reference instance of <code>DEFAULT_CATALOG</code>
*/
public static final DefaultCatalog DEFAULT_CATALOG = new DefaultCatalog();
/**
* The schema <code>public</code>.
*/
public final Public PUBLIC = Public.PUBLIC;
/**
* No further instances allowed
*/
private DefaultCatalog() {
super("");
}
@Override
public final List<Schema> getSchemas() {
return Arrays.asList(
Public.PUBLIC
);
}
/**
* A reference to the 3.19 minor release of the code generator. If this
* doesn't compile, it's because the runtime library uses an older minor
* release, namely: 3.19. You can turn off the generation of this reference
* by specifying /configuration/generator/generate/jooqVersionReference
*/
private static final String REQUIRE_RUNTIME_JOOQ_VERSION = Constants.VERSION_3_19;
}
@@ -0,0 +1,75 @@
package com.baeldung.jooq.jointables;
import static org.jooq.impl.DSL.field;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.SelectJoinStep;
import com.baeldung.jooq.jointables.public_.Tables;
public class JoinTables {
public static Result<Record> usingJoinMethod(DSLContext context) {
SelectJoinStep<Record> query = context.select()
.from(Tables.BOOK)
.join(Tables.BOOKAUTHOR)
.on(field(Tables.BOOK.AUTHOR_ID).eq(field(Tables.BOOKAUTHOR.ID)));
return query.fetch();
}
public static Result<Record> usingMultipleJoinMethod(DSLContext context) {
SelectJoinStep<Record> query = context.select()
.from(Tables.BOOK)
.join(Tables.BOOKAUTHOR)
.on(field(Tables.BOOK.AUTHOR_ID).eq(field(Tables.BOOKAUTHOR.ID)))
.join(Tables.STORE)
.on(field(Tables.BOOK.STORE_ID).eq(field(Tables.STORE.ID)));
return query.fetch();
}
public static Result<Record> usingLeftOuterJoinMethod(DSLContext context) {
SelectJoinStep<Record> query = context.select()
.from(Tables.BOOK)
.leftOuterJoin(Tables.BOOKAUTHOR)
.on(field(Tables.BOOK.AUTHOR_ID).eq(field(Tables.BOOKAUTHOR.ID)));
return query.fetch();
}
public static Result<Record> usingRightOuterJoinMethod(DSLContext context) {
SelectJoinStep<Record> query = context.select()
.from(Tables.BOOK)
.rightOuterJoin(Tables.BOOKAUTHOR)
.on(field(Tables.BOOK.AUTHOR_ID).eq(field(Tables.BOOKAUTHOR.ID)));
return query.fetch();
}
public static Result<Record> usingFullOuterJoinMethod(DSLContext context) {
SelectJoinStep<Record> query = context.select()
.from(Tables.BOOK)
.fullOuterJoin(Tables.BOOKAUTHOR)
.on(field(Tables.BOOK.AUTHOR_ID).eq(field(Tables.BOOKAUTHOR.ID)));
return query.fetch();
}
public static Result<Record> usingNaturalJoinMethod(DSLContext context) {
SelectJoinStep<Record> query = context.select()
.from(Tables.BOOK)
.naturalJoin(Tables.BOOKAUTHOR);
return query.fetch();
}
public static Result<Record> usingCrossJoinMethod(DSLContext context) {
SelectJoinStep<Record> query = context.select()
.from(Tables.STORE)
.crossJoin(Tables.BOOK);
return query.fetch();
}
public static void printResult(Result<Record> result) {
for (Record record : result) {
System.out.println(record);
}
}
}
@@ -0,0 +1,34 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_;
import com.baeldung.jooq.jointables.public_.tables.Book;
import com.baeldung.jooq.jointables.public_.tables.Bookauthor;
import com.baeldung.jooq.jointables.public_.tables.Store;
import com.baeldung.jooq.jointables.public_.tables.records.BookRecord;
import com.baeldung.jooq.jointables.public_.tables.records.BookauthorRecord;
import com.baeldung.jooq.jointables.public_.tables.records.StoreRecord;
import org.jooq.TableField;
import org.jooq.UniqueKey;
import org.jooq.impl.DSL;
import org.jooq.impl.Internal;
/**
* A class modelling foreign key relationships and constraints of tables in
* public.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class Keys {
// -------------------------------------------------------------------------
// UNIQUE and PRIMARY KEY definitions
// -------------------------------------------------------------------------
public static final UniqueKey<BookRecord> BOOK_PKEY = Internal.createUniqueKey(Book.BOOK, DSL.name("Book_pkey"), new TableField[] { Book.BOOK.ID }, true);
public static final UniqueKey<BookauthorRecord> AUTHOR_PKEY = Internal.createUniqueKey(Bookauthor.BOOKAUTHOR, DSL.name("Author_pkey"), new TableField[] { Bookauthor.BOOKAUTHOR.ID }, true);
public static final UniqueKey<StoreRecord> STORE_PKEY = Internal.createUniqueKey(Store.STORE, DSL.name("Store_pkey"), new TableField[] { Store.STORE.ID }, true);
}
@@ -0,0 +1,69 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_;
import com.baeldung.jooq.jointables.DefaultCatalog;
import com.baeldung.jooq.jointables.public_.tables.Book;
import com.baeldung.jooq.jointables.public_.tables.Bookauthor;
import com.baeldung.jooq.jointables.public_.tables.Store;
import java.util.Arrays;
import java.util.List;
import org.jooq.Catalog;
import org.jooq.Table;
import org.jooq.impl.SchemaImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class Public extends SchemaImpl {
private static final long serialVersionUID = 1L;
/**
* The reference instance of <code>public</code>
*/
public static final Public PUBLIC = new Public();
/**
* The table <code>public.Book</code>.
*/
public final Book BOOK = Book.BOOK;
/**
* The table <code>public.BookAuthor</code>.
*/
public final Bookauthor BOOKAUTHOR = Bookauthor.BOOKAUTHOR;
/**
* The table <code>public.Store</code>.
*/
public final Store STORE = Store.STORE;
/**
* No further instances allowed
*/
private Public() {
super("public", null);
}
@Override
public Catalog getCatalog() {
return DefaultCatalog.DEFAULT_CATALOG;
}
@Override
public final List<Table<?>> getTables() {
return Arrays.asList(
Book.BOOK,
Bookauthor.BOOKAUTHOR,
Store.STORE
);
}
}
@@ -0,0 +1,32 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_;
import com.baeldung.jooq.jointables.public_.tables.Book;
import com.baeldung.jooq.jointables.public_.tables.Bookauthor;
import com.baeldung.jooq.jointables.public_.tables.Store;
/**
* Convenience access to all tables in public.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class Tables {
/**
* The table <code>public.Book</code>.
*/
public static final Book BOOK = Book.BOOK;
/**
* The table <code>public.BookAuthor</code>.
*/
public static final Bookauthor BOOKAUTHOR = Bookauthor.BOOKAUTHOR;
/**
* The table <code>public.Store</code>.
*/
public static final Store STORE = Store.STORE;
}
@@ -0,0 +1,238 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_.tables;
import com.baeldung.jooq.jointables.public_.Keys;
import com.baeldung.jooq.jointables.public_.Public;
import com.baeldung.jooq.jointables.public_.tables.records.BookRecord;
import java.util.Collection;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.PlainSQL;
import org.jooq.QueryPart;
import org.jooq.SQL;
import org.jooq.Schema;
import org.jooq.Select;
import org.jooq.Stringly;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableOptions;
import org.jooq.UniqueKey;
import org.jooq.impl.DSL;
import org.jooq.impl.SQLDataType;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class Book extends TableImpl<BookRecord> {
private static final long serialVersionUID = 1L;
/**
* The reference instance of <code>public.Book</code>
*/
public static final Book BOOK = new Book();
/**
* The class holding records for this type
*/
@Override
public Class<BookRecord> getRecordType() {
return BookRecord.class;
}
/**
* The column <code>public.Book.id</code>.
*/
public final TableField<BookRecord, Integer> ID = createField(DSL.name("id"), SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>public.Book.author_id</code>.
*/
public final TableField<BookRecord, Integer> AUTHOR_ID = createField(DSL.name("author_id"), SQLDataType.INTEGER, this, "");
/**
* The column <code>public.Book.title</code>.
*/
public final TableField<BookRecord, String> TITLE = createField(DSL.name("title"), SQLDataType.VARCHAR, this, "");
/**
* The column <code>public.Book.description</code>.
*/
public final TableField<BookRecord, String> DESCRIPTION = createField(DSL.name("description"), SQLDataType.VARCHAR, this, "");
/**
* The column <code>public.Book.store_id</code>.
*/
public final TableField<BookRecord, Integer> STORE_ID = createField(DSL.name("store_id"), SQLDataType.INTEGER, this, "");
private Book(Name alias, Table<BookRecord> aliased) {
this(alias, aliased, (Field<?>[]) null, null);
}
private Book(Name alias, Table<BookRecord> aliased, Field<?>[] parameters, Condition where) {
super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table(), where);
}
/**
* Create an aliased <code>public.Book</code> table reference
*/
public Book(String alias) {
this(DSL.name(alias), BOOK);
}
/**
* Create an aliased <code>public.Book</code> table reference
*/
public Book(Name alias) {
this(alias, BOOK);
}
/**
* Create a <code>public.Book</code> table reference
*/
public Book() {
this(DSL.name("Book"), null);
}
@Override
public Schema getSchema() {
return aliased() ? null : Public.PUBLIC;
}
@Override
public UniqueKey<BookRecord> getPrimaryKey() {
return Keys.BOOK_PKEY;
}
@Override
public Book as(String alias) {
return new Book(DSL.name(alias), this);
}
@Override
public Book as(Name alias) {
return new Book(alias, this);
}
@Override
public Book as(Table<?> alias) {
return new Book(alias.getQualifiedName(), this);
}
/**
* Rename this table
*/
@Override
public Book rename(String name) {
return new Book(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public Book rename(Name name) {
return new Book(name, null);
}
/**
* Rename this table
*/
@Override
public Book rename(Table<?> name) {
return new Book(name.getQualifiedName(), null);
}
/**
* Create an inline derived table from this table
*/
@Override
public Book where(Condition condition) {
return new Book(getQualifiedName(), aliased() ? this : null, null, condition);
}
/**
* Create an inline derived table from this table
*/
@Override
public Book where(Collection<? extends Condition> conditions) {
return where(DSL.and(conditions));
}
/**
* Create an inline derived table from this table
*/
@Override
public Book where(Condition... conditions) {
return where(DSL.and(conditions));
}
/**
* Create an inline derived table from this table
*/
@Override
public Book where(Field<Boolean> condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Book where(SQL condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Book where(@Stringly.SQL String condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Book where(@Stringly.SQL String condition, Object... binds) {
return where(DSL.condition(condition, binds));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Book where(@Stringly.SQL String condition, QueryPart... parts) {
return where(DSL.condition(condition, parts));
}
/**
* Create an inline derived table from this table
*/
@Override
public Book whereExists(Select<?> select) {
return where(DSL.exists(select));
}
/**
* Create an inline derived table from this table
*/
@Override
public Book whereNotExists(Select<?> select) {
return where(DSL.notExists(select));
}
}
@@ -0,0 +1,228 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_.tables;
import com.baeldung.jooq.jointables.public_.Keys;
import com.baeldung.jooq.jointables.public_.Public;
import com.baeldung.jooq.jointables.public_.tables.records.BookauthorRecord;
import java.util.Collection;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.PlainSQL;
import org.jooq.QueryPart;
import org.jooq.SQL;
import org.jooq.Schema;
import org.jooq.Select;
import org.jooq.Stringly;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableOptions;
import org.jooq.UniqueKey;
import org.jooq.impl.DSL;
import org.jooq.impl.SQLDataType;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class Bookauthor extends TableImpl<BookauthorRecord> {
private static final long serialVersionUID = 1L;
/**
* The reference instance of <code>public.BookAuthor</code>
*/
public static final Bookauthor BOOKAUTHOR = new Bookauthor();
/**
* The class holding records for this type
*/
@Override
public Class<BookauthorRecord> getRecordType() {
return BookauthorRecord.class;
}
/**
* The column <code>public.BookAuthor.id</code>.
*/
public final TableField<BookauthorRecord, Integer> ID = createField(DSL.name("id"), SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>public.BookAuthor.name</code>.
*/
public final TableField<BookauthorRecord, String> NAME = createField(DSL.name("name"), SQLDataType.VARCHAR.nullable(false), this, "");
/**
* The column <code>public.BookAuthor.country</code>.
*/
public final TableField<BookauthorRecord, String> COUNTRY = createField(DSL.name("country"), SQLDataType.VARCHAR, this, "");
private Bookauthor(Name alias, Table<BookauthorRecord> aliased) {
this(alias, aliased, (Field<?>[]) null, null);
}
private Bookauthor(Name alias, Table<BookauthorRecord> aliased, Field<?>[] parameters, Condition where) {
super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table(), where);
}
/**
* Create an aliased <code>public.BookAuthor</code> table reference
*/
public Bookauthor(String alias) {
this(DSL.name(alias), BOOKAUTHOR);
}
/**
* Create an aliased <code>public.BookAuthor</code> table reference
*/
public Bookauthor(Name alias) {
this(alias, BOOKAUTHOR);
}
/**
* Create a <code>public.BookAuthor</code> table reference
*/
public Bookauthor() {
this(DSL.name("BookAuthor"), null);
}
@Override
public Schema getSchema() {
return aliased() ? null : Public.PUBLIC;
}
@Override
public UniqueKey<BookauthorRecord> getPrimaryKey() {
return Keys.AUTHOR_PKEY;
}
@Override
public Bookauthor as(String alias) {
return new Bookauthor(DSL.name(alias), this);
}
@Override
public Bookauthor as(Name alias) {
return new Bookauthor(alias, this);
}
@Override
public Bookauthor as(Table<?> alias) {
return new Bookauthor(alias.getQualifiedName(), this);
}
/**
* Rename this table
*/
@Override
public Bookauthor rename(String name) {
return new Bookauthor(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public Bookauthor rename(Name name) {
return new Bookauthor(name, null);
}
/**
* Rename this table
*/
@Override
public Bookauthor rename(Table<?> name) {
return new Bookauthor(name.getQualifiedName(), null);
}
/**
* Create an inline derived table from this table
*/
@Override
public Bookauthor where(Condition condition) {
return new Bookauthor(getQualifiedName(), aliased() ? this : null, null, condition);
}
/**
* Create an inline derived table from this table
*/
@Override
public Bookauthor where(Collection<? extends Condition> conditions) {
return where(DSL.and(conditions));
}
/**
* Create an inline derived table from this table
*/
@Override
public Bookauthor where(Condition... conditions) {
return where(DSL.and(conditions));
}
/**
* Create an inline derived table from this table
*/
@Override
public Bookauthor where(Field<Boolean> condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Bookauthor where(SQL condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Bookauthor where(@Stringly.SQL String condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Bookauthor where(@Stringly.SQL String condition, Object... binds) {
return where(DSL.condition(condition, binds));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Bookauthor where(@Stringly.SQL String condition, QueryPart... parts) {
return where(DSL.condition(condition, parts));
}
/**
* Create an inline derived table from this table
*/
@Override
public Bookauthor whereExists(Select<?> select) {
return where(DSL.exists(select));
}
/**
* Create an inline derived table from this table
*/
@Override
public Bookauthor whereNotExists(Select<?> select) {
return where(DSL.notExists(select));
}
}
@@ -0,0 +1,223 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_.tables;
import com.baeldung.jooq.jointables.public_.Keys;
import com.baeldung.jooq.jointables.public_.Public;
import com.baeldung.jooq.jointables.public_.tables.records.StoreRecord;
import java.util.Collection;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.PlainSQL;
import org.jooq.QueryPart;
import org.jooq.SQL;
import org.jooq.Schema;
import org.jooq.Select;
import org.jooq.Stringly;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableOptions;
import org.jooq.UniqueKey;
import org.jooq.impl.DSL;
import org.jooq.impl.SQLDataType;
import org.jooq.impl.TableImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class Store extends TableImpl<StoreRecord> {
private static final long serialVersionUID = 1L;
/**
* The reference instance of <code>public.Store</code>
*/
public static final Store STORE = new Store();
/**
* The class holding records for this type
*/
@Override
public Class<StoreRecord> getRecordType() {
return StoreRecord.class;
}
/**
* The column <code>public.Store.id</code>.
*/
public final TableField<StoreRecord, Integer> ID = createField(DSL.name("id"), SQLDataType.INTEGER.nullable(false), this, "");
/**
* The column <code>public.Store.name</code>.
*/
public final TableField<StoreRecord, String> NAME = createField(DSL.name("name"), SQLDataType.VARCHAR.nullable(false), this, "");
private Store(Name alias, Table<StoreRecord> aliased) {
this(alias, aliased, (Field<?>[]) null, null);
}
private Store(Name alias, Table<StoreRecord> aliased, Field<?>[] parameters, Condition where) {
super(alias, null, aliased, parameters, DSL.comment(""), TableOptions.table(), where);
}
/**
* Create an aliased <code>public.Store</code> table reference
*/
public Store(String alias) {
this(DSL.name(alias), STORE);
}
/**
* Create an aliased <code>public.Store</code> table reference
*/
public Store(Name alias) {
this(alias, STORE);
}
/**
* Create a <code>public.Store</code> table reference
*/
public Store() {
this(DSL.name("Store"), null);
}
@Override
public Schema getSchema() {
return aliased() ? null : Public.PUBLIC;
}
@Override
public UniqueKey<StoreRecord> getPrimaryKey() {
return Keys.STORE_PKEY;
}
@Override
public Store as(String alias) {
return new Store(DSL.name(alias), this);
}
@Override
public Store as(Name alias) {
return new Store(alias, this);
}
@Override
public Store as(Table<?> alias) {
return new Store(alias.getQualifiedName(), this);
}
/**
* Rename this table
*/
@Override
public Store rename(String name) {
return new Store(DSL.name(name), null);
}
/**
* Rename this table
*/
@Override
public Store rename(Name name) {
return new Store(name, null);
}
/**
* Rename this table
*/
@Override
public Store rename(Table<?> name) {
return new Store(name.getQualifiedName(), null);
}
/**
* Create an inline derived table from this table
*/
@Override
public Store where(Condition condition) {
return new Store(getQualifiedName(), aliased() ? this : null, null, condition);
}
/**
* Create an inline derived table from this table
*/
@Override
public Store where(Collection<? extends Condition> conditions) {
return where(DSL.and(conditions));
}
/**
* Create an inline derived table from this table
*/
@Override
public Store where(Condition... conditions) {
return where(DSL.and(conditions));
}
/**
* Create an inline derived table from this table
*/
@Override
public Store where(Field<Boolean> condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Store where(SQL condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Store where(@Stringly.SQL String condition) {
return where(DSL.condition(condition));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Store where(@Stringly.SQL String condition, Object... binds) {
return where(DSL.condition(condition, binds));
}
/**
* Create an inline derived table from this table
*/
@Override
@PlainSQL
public Store where(@Stringly.SQL String condition, QueryPart... parts) {
return where(DSL.condition(condition, parts));
}
/**
* Create an inline derived table from this table
*/
@Override
public Store whereExists(Select<?> select) {
return where(DSL.exists(select));
}
/**
* Create an inline derived table from this table
*/
@Override
public Store whereNotExists(Select<?> select) {
return where(DSL.notExists(select));
}
}
@@ -0,0 +1,124 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_.tables.records;
import com.baeldung.jooq.jointables.public_.tables.Book;
import org.jooq.Record1;
import org.jooq.impl.UpdatableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class BookRecord extends UpdatableRecordImpl<BookRecord> {
private static final long serialVersionUID = 1L;
/**
* Setter for <code>public.Book.id</code>.
*/
public void setId(Integer value) {
set(0, value);
}
/**
* Getter for <code>public.Book.id</code>.
*/
public Integer getId() {
return (Integer) get(0);
}
/**
* Setter for <code>public.Book.author_id</code>.
*/
public void setAuthorId(Integer value) {
set(1, value);
}
/**
* Getter for <code>public.Book.author_id</code>.
*/
public Integer getAuthorId() {
return (Integer) get(1);
}
/**
* Setter for <code>public.Book.title</code>.
*/
public void setTitle(String value) {
set(2, value);
}
/**
* Getter for <code>public.Book.title</code>.
*/
public String getTitle() {
return (String) get(2);
}
/**
* Setter for <code>public.Book.description</code>.
*/
public void setDescription(String value) {
set(3, value);
}
/**
* Getter for <code>public.Book.description</code>.
*/
public String getDescription() {
return (String) get(3);
}
/**
* Setter for <code>public.Book.store_id</code>.
*/
public void setStoreId(Integer value) {
set(4, value);
}
/**
* Getter for <code>public.Book.store_id</code>.
*/
public Integer getStoreId() {
return (Integer) get(4);
}
// -------------------------------------------------------------------------
// Primary key information
// -------------------------------------------------------------------------
@Override
public Record1<Integer> key() {
return (Record1) super.key();
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached BookRecord
*/
public BookRecord() {
super(Book.BOOK);
}
/**
* Create a detached, initialised BookRecord
*/
public BookRecord(Integer id, Integer authorId, String title, String description, Integer storeId) {
super(Book.BOOK);
setId(id);
setAuthorId(authorId);
setTitle(title);
setDescription(description);
setStoreId(storeId);
resetChangedOnNotNull();
}
}
@@ -0,0 +1,94 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_.tables.records;
import com.baeldung.jooq.jointables.public_.tables.Bookauthor;
import org.jooq.Record1;
import org.jooq.impl.UpdatableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class BookauthorRecord extends UpdatableRecordImpl<BookauthorRecord> {
private static final long serialVersionUID = 1L;
/**
* Setter for <code>public.BookAuthor.id</code>.
*/
public void setId(Integer value) {
set(0, value);
}
/**
* Getter for <code>public.BookAuthor.id</code>.
*/
public Integer getId() {
return (Integer) get(0);
}
/**
* Setter for <code>public.BookAuthor.name</code>.
*/
public void setName(String value) {
set(1, value);
}
/**
* Getter for <code>public.BookAuthor.name</code>.
*/
public String getName() {
return (String) get(1);
}
/**
* Setter for <code>public.BookAuthor.country</code>.
*/
public void setCountry(String value) {
set(2, value);
}
/**
* Getter for <code>public.BookAuthor.country</code>.
*/
public String getCountry() {
return (String) get(2);
}
// -------------------------------------------------------------------------
// Primary key information
// -------------------------------------------------------------------------
@Override
public Record1<Integer> key() {
return (Record1) super.key();
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached BookauthorRecord
*/
public BookauthorRecord() {
super(Bookauthor.BOOKAUTHOR);
}
/**
* Create a detached, initialised BookauthorRecord
*/
public BookauthorRecord(Integer id, String name, String country) {
super(Bookauthor.BOOKAUTHOR);
setId(id);
setName(name);
setCountry(country);
resetChangedOnNotNull();
}
}
@@ -0,0 +1,79 @@
/*
* This file is generated by jOOQ.
*/
package com.baeldung.jooq.jointables.public_.tables.records;
import com.baeldung.jooq.jointables.public_.tables.Store;
import org.jooq.Record1;
import org.jooq.impl.UpdatableRecordImpl;
/**
* This class is generated by jOOQ.
*/
@SuppressWarnings({ "all", "unchecked", "rawtypes", "this-escape" })
public class StoreRecord extends UpdatableRecordImpl<StoreRecord> {
private static final long serialVersionUID = 1L;
/**
* Setter for <code>public.Store.id</code>.
*/
public void setId(Integer value) {
set(0, value);
}
/**
* Getter for <code>public.Store.id</code>.
*/
public Integer getId() {
return (Integer) get(0);
}
/**
* Setter for <code>public.Store.name</code>.
*/
public void setName(String value) {
set(1, value);
}
/**
* Getter for <code>public.Store.name</code>.
*/
public String getName() {
return (String) get(1);
}
// -------------------------------------------------------------------------
// Primary key information
// -------------------------------------------------------------------------
@Override
public Record1<Integer> key() {
return (Record1) super.key();
}
// -------------------------------------------------------------------------
// Constructors
// -------------------------------------------------------------------------
/**
* Create a detached StoreRecord
*/
public StoreRecord() {
super(Store.STORE);
}
/**
* Create a detached, initialised StoreRecord
*/
public StoreRecord(Integer id, String name) {
super(Store.STORE);
setId(id);
setName(name);
resetChangedOnNotNull();
}
}
@@ -0,0 +1,111 @@
package com.baeldung.jooq.jointables;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.sql.Connection;
import java.sql.DriverManager;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.SQLDialect;
import org.jooq.impl.DSL;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.baeldung.jooq.jointables.public_.Tables;
import com.baeldung.jooq.jointables.public_.tables.Book;
import com.baeldung.jooq.jointables.public_.tables.Bookauthor;
import com.baeldung.jooq.jointables.public_.tables.Store;
public class JoinTablesLiveTest {
static DSLContext context;
@BeforeClass
public static void setUp() throws Exception {
// URL jooqConfigURL = getClass().getClassLoader().getResource("jooq-config-2.xml");
// File file = new File(jooqConfigURL.getFile());
// GenerationTool.generate(Files.readString(file.toPath()));
String url = "jdbc:postgresql://localhost:5432/postgres";
String username = "postgres";
String password = "";
Connection conn = DriverManager.getConnection(url, username, password);
context = DSL.using(conn, SQLDialect.POSTGRES);
context.insertInto(Tables.STORE, Store.STORE.ID, Store.STORE.NAME)
.values(1, "ABC Branch I ")
.values(2, "ABC Branch II")
.execute();
context.insertInto(Tables.BOOK, Book.BOOK.ID, Book.BOOK.TITLE, Book.BOOK.DESCRIPTION, Book.BOOK.AUTHOR_ID, Book.BOOK.STORE_ID)
.values(1, "Book 1", "This is book 1", 1, 1)
.values(2, "Book 2", "This is book 2", 2, 2)
.values(3, "Book 3", "This is book 3", 1, 2)
.values(4, "Book 4", "This is book 4", 5, 1)
.execute();
context.insertInto(Tables.BOOKAUTHOR, Bookauthor.BOOKAUTHOR.ID, Bookauthor.BOOKAUTHOR.NAME, Bookauthor.BOOKAUTHOR.COUNTRY)
.values(1, "John Smith", "Japan")
.values(2, "William Walce", "Japan")
.values(3, "Marry Sity", "South Korea")
.values(4, "Morry Toh", "England")
.execute();
}
@AfterClass
public static void cleanup() throws Exception {
context.truncateTable(Store.STORE)
.execute();
context.truncateTable(Book.BOOK)
.execute();
context.truncateTable(Bookauthor.BOOKAUTHOR)
.execute();
}
@Test
public void _whenUsingJoinMethod_thenQueryExecuted() {
Result<Record> result = JoinTables.usingJoinMethod(context);
assertEquals(3, result.size());
}
@Test
public void _whenUsingMultipleJoinMethod_thenQueryExecuted() {
Result<Record> result = JoinTables.usingMultipleJoinMethod(context);
assertEquals(3, result.size());
}
@Test
public void givenContext_whenUsingLeftOuterJoinMethod_thenQueryExecuted() {
Result<Record> result = JoinTables.usingLeftOuterJoinMethod(context);
assertEquals(4, result.size());
}
@Test
public void whenUsingRightOuterJoinMethod_thenQueryExecuted() {
Result<Record> result = JoinTables.usingRightOuterJoinMethod(context);
assertEquals(5, result.size());
}
@Test
public void whenUsingFullOuterJoinMethod_thenQueryExecuted() {
Result<Record> result = JoinTables.usingFullOuterJoinMethod(context);
assertEquals(6, result.size());
}
@Test
public void whenUsingNaturalJoinMethod_thenQueryExecuted() {
Result<Record> result = JoinTables.usingNaturalJoinMethod(context);
assertEquals(4, result.size());
}
@Test
public void whenUsingCrossJoinMethod_thenQueryExecuted() {
Result<Record> result = JoinTables.usingCrossJoinMethod(context);
assertEquals(8, result.size());
}
}
@@ -0,0 +1,19 @@
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.15.0.xsd">
<jdbc>
<driver>org.postgresql.Driver</driver>
<url>jdbc:postgresql://localhost:5432/postgres</url>
<user>postgres</user>
<password></password>
</jdbc>
<generator>
<database>
<name>org.jooq.meta.postgres.PostgresDatabase</name>
<includes>Store|Book|BookAuthor</includes>
<excludes></excludes>
</database>
<target>
<packageName>com.baeldung.jooq.jointables</packageName>
<directory>src/main/java</directory>
</target>
</generator>
</configuration>
+1
View File
@@ -1,2 +1,3 @@
### Relevant Articles:
- [Introduction to Liquibase Rollback](http://www.baeldung.com/liquibase-rollback)
- [Creating PostgreSQL Schema Before Liquibase Execution](https://www.baeldung.com/java-postgresql-create-schema-before-liquibase)
+2
View File
@@ -24,6 +24,7 @@
<module>core-java-persistence-2</module>
<module>core-java-persistence-3</module>
<module>couchbase</module>
<module>duckdb</module>
<module>elasticsearch</module>
<module>flyway</module>
<module>flyway-repair</module>
@@ -88,6 +89,7 @@
<module>spring-data-jpa-query</module>
<module>spring-data-jpa-query-2</module>
<module>spring-data-jpa-query-3</module>
<module>spring-data-jpa-query-4</module>
<module>spring-data-jpa-repo</module>
<module>spring-data-jpa-repo-2</module>
<module>spring-data-jpa-repo-4</module>
@@ -60,6 +60,11 @@
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.tx.version}</version>
</dependency>
</dependencies>
<build>
@@ -84,6 +89,7 @@
<modelmapper.version>3.2.0</modelmapper.version>
<commons-codec.version>1.16.1</commons-codec.version>
<lombok.version>1.18.30</lombok.version>
<spring.tx.version>6.1.4</spring.tx.version>
</properties>
</project>
@@ -0,0 +1,23 @@
package com.baeldung.transactionalandasync;
import jakarta.persistence.*;
import lombok.*;
import java.math.BigDecimal;
@Entity
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(of = {"id"})
@Table(name = "account")
@Data
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "balance")
private BigDecimal balance;
}
@@ -0,0 +1,6 @@
package com.baeldung.transactionalandasync;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AccountRepository extends JpaRepository<Account, Long> {
}
@@ -0,0 +1,41 @@
package com.baeldung.transactionalandasync;
import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
@Service
@AllArgsConstructor
@Transactional
public class AccountService {
private final AccountRepository accountRepository;
@Async
public void transferAsync(Long depositorId, Long favoredId, BigDecimal amount) {
transfer(depositorId, favoredId, amount);
printReceipt();
}
@Transactional
public void transfer(Long depositorId, Long favoredId, BigDecimal amount) {
Account depositorAccount = accountRepository.findById(depositorId)
.orElseThrow(IllegalArgumentException::new);
Account favoredAccount = accountRepository.findById(favoredId)
.orElseThrow(IllegalArgumentException::new);
depositorAccount.setBalance(depositorAccount.getBalance().subtract(amount));
favoredAccount.setBalance(favoredAccount.getBalance().add(amount));
accountRepository.save(depositorAccount);
accountRepository.save(favoredAccount);
}
public void printReceipt() {
// logic to print the receipt
}
}
@@ -0,0 +1,12 @@
package com.baeldung.transactionalandasync;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BankAccountApplication {
public static void main(String[] args) {
SpringApplication.run(BankAccountApplication.class, args);
}
}
@@ -70,7 +70,6 @@
</dependencies>
<properties>
<mockito.version>2.23.0</mockito.version>
<validation-api.version>2.0.1.Final</validation-api.version>
<mysql-connector-java.version>8.2.0</mysql-connector-java.version>
<start-class>com.baeldung.boot.Application</start-class>
@@ -136,6 +136,12 @@
<type>so</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.14.13</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -5,8 +5,6 @@ import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.Application;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class SpringContextTest {
@@ -0,0 +1,57 @@
package com.baeldung.criteriaquery;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import org.springframework.data.jpa.domain.Specification;
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String title;
private String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
public Book() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
static Specification<Book> hasAuthor(String author) {
return (book, cq, cb) -> cb.equal(book.get("author"), author);
}
static Specification<Book> titleContains(String title) {
return (book, cq, cb) -> cb.like(book.get("title"), "%" + title + "%");
}
}
@@ -0,0 +1,9 @@
package com.baeldung.criteriaquery;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
@Repository
interface BookRepository extends JpaRepository<Book, Long>, BookRepositoryCustom, JpaSpecificationExecutor<Book> {
}
@@ -0,0 +1,9 @@
package com.baeldung.criteriaquery;
import java.util.List;
interface BookRepositoryCustom {
List<Book> findBooksByAuthorNameAndTitle(String authorName, String title);
}
@@ -0,0 +1,39 @@
package com.baeldung.criteriaquery;
import jakarta.persistence.EntityManager;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
@Repository
public class BookRepositoryImpl implements BookRepositoryCustom {
@Autowired
private EntityManager em;
@Override
public List<Book> findBooksByAuthorNameAndTitle(String authorName, String title) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Book> cq = cb.createQuery(Book.class);
Root<Book> book = cq.from(Book.class);
List<Predicate> predicates = new ArrayList<>();
if (authorName != null) {
predicates.add(cb.equal(book.get("author"), authorName));
}
if (title != null) {
predicates.add(cb.like(book.get("title"), "%" + title + "%"));
}
cq.where(predicates.toArray(new Predicate[0]));
return em.createQuery(cq).getResultList();
}
}
@@ -0,0 +1,50 @@
package com.baeldung.criteriaquery;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
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.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import static com.baeldung.criteriaquery.Book.hasAuthor;
import static com.baeldung.criteriaquery.Book.titleContains;
import static org.junit.Assert.assertEquals;
import static org.springframework.data.jpa.domain.Specification.where;
@DataJpaTest(showSql = false)
@RunWith(SpringRunner.class)
public class CriteriaQueryIntegrationTest {
@PersistenceContext
private EntityManager entityManager;
@Autowired
private BookRepository repository;
@Before
public void before() {
entityManager.persist(new Book("title1", "author1"));
entityManager.persist(new Book("title2", "author2"));
}
@Test
public void givenAuthorAndTextInTitle_whenFindWithSpecification_ThenFound() {
List<Book> books = repository.findAll(where(hasAuthor("author1")).and(titleContains("1")));
assertEquals(1, books.size());
assertEquals("author1", books.get(0).getAuthor());
assertEquals("title1", books.get(0).getTitle());
}
@Test
public void givenAuthorAndTextInTitle_whenFindWithCriteriaQuery_ThenFound() {
List<Book> books = repository.findBooksByAuthorNameAndTitle("author2", "2");
assertEquals(1, books.size());
assertEquals("author2", books.get(0).getAuthor());
assertEquals("title2", books.get(0).getTitle());
}
}
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-data-jpa-query-4</artifactId>
<name>spring-data-jpa-query-4</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
</dependency>
</dependencies>
<properties>
<postgresql.version>42.7.1</postgresql.version>
</properties>
</project>
@@ -0,0 +1,24 @@
package com.baeldung.spring.data.jpa.getnextseq;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "mySeqGen")
@SequenceGenerator(name = "mySeqGen", sequenceName = "my_sequence_name", allocationSize = 1)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
@@ -0,0 +1,13 @@
package com.baeldung.spring.data.jpa.getnextseq;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyEntityApplication {
public static void main(String[] args) {
SpringApplication.run(MyEntityApplication.class);
}
}
@@ -0,0 +1,12 @@
package com.baeldung.spring.data.jpa.getnextseq;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@Repository
public interface MyEntityRepository extends JpaRepository<MyEntity, Long> {
@Query(value = "SELECT NEXTVAL('my_sequence_name')", nativeQuery = true)
Long getNextSequenceValue();
}
@@ -0,0 +1,22 @@
package com.baeldung.spring.data.jpa.getnextseq;
import java.math.BigInteger;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
@Service
public class MyEntityService {
@PersistenceContext
private EntityManager entityManager;
public Long getNextSequenceValue(String sequenceName) {
BigInteger nextValue = (BigInteger) entityManager.createNativeQuery("SELECT NEXTVAL(:sequenceName)")
.setParameter("sequenceName", sequenceName)
.getSingleResult();
return nextValue.longValue();
}
}
@@ -0,0 +1,52 @@
package com.baeldung.spring.data.jpa.queryjsonb;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@Column(columnDefinition = "jsonb")
private String attributes;
public Product() {
}
public Product(String name, String attributes) {
this.name = name;
this.attributes = attributes;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAttributes() {
return attributes;
}
public void setAttributes(String attributes) {
this.attributes = attributes;
}
}
@@ -0,0 +1,12 @@
package com.baeldung.spring.data.jpa.queryjsonb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class);
}
}
@@ -0,0 +1,24 @@
package com.baeldung.spring.data.jpa.queryjsonb;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ProductRepository extends JpaRepository<Product, Long>, JpaSpecificationExecutor<Product> {
@Query(value = "SELECT * FROM product WHERE attributes ->> ?1 = ?2", nativeQuery = true)
List<Product> findByAttribute(String key, String value);
@Query(value = "SELECT * FROM product WHERE attributes -> ?1 ->> ?2 = ?3", nativeQuery = true)
List<Product> findByNestedAttribute(String key1, String key2, String value);
@Query(value = "SELECT * FROM product WHERE jsonb_extract_path_text(attributes, ?1) = ?2", nativeQuery = true)
List<Product> findByJsonPath(String path, String value);
@Query(value = "SELECT * FROM product WHERE jsonb_extract_path_text(attributes, ?1, ?2) = ?3", nativeQuery = true)
List<Product> findByNestedJsonPath(String key1, String key2, String value);
}
@@ -0,0 +1,22 @@
package com.baeldung.spring.data.jpa.queryjsonb;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
public class ProductSpecification implements Specification<Product> {
private final String key;
private final String value;
public ProductSpecification(String key, String value) {
this.key = key; this.value = value;
}
@Override
public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(cb.function("jsonb_extract_path_text", String.class, root.get("attributes"), cb.literal(key)), value);
}
}
@@ -0,0 +1,10 @@
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
spring.jpa.properties.hibernate.format_sql=true
@@ -0,0 +1,47 @@
package com.baeldung.spring.data.jpa.getnextseq;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
@SpringBootTest
@ActiveProfiles("test")
@Sql(scripts = "/testsequence.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public class MyEntityRepositoryIntegrationTest {
@Autowired
private MyEntityRepository myEntityRepository;
@Autowired
private MyEntityService myEntityService;
@Test
void whenUsingSequenceGenerator_thenNextValueReturned() {
MyEntity entity = new MyEntity();
myEntityRepository.save(entity);
long generatedId = entity.getId();
assertNotNull(generatedId);
assertEquals(1L, generatedId);
}
@Test
void whenUsingCustomQuery_thenNextValueReturned() {
long generatedId = myEntityRepository.getNextSequenceValue();
assertNotNull(generatedId);
assertEquals(1L, generatedId);
}
@Test
void whenUsingEntityManager_thenNextValueReturned() {
long generatedId = myEntityService.getNextSequenceValue("my_sequence_name");
assertNotNull(generatedId);
assertEquals(1L, generatedId);
}
}
@@ -0,0 +1,77 @@
package com.baeldung.spring.data.jpa.queryjsonb;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.List;
import javax.transaction.Transactional;
import org.junit.Before;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.domain.PageImpl;
import org.springframework.test.annotation.Commit;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.transaction.annotation.Propagation;
import com.fasterxml.jackson.databind.ObjectMapper;
@SpringBootTest
@ActiveProfiles("test")
@Sql(scripts = "/testdata.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public class ProductRepositoryLiveTest {
@Autowired
private ProductRepository productRepository;
@Test
void whenFindByAttribute_thenReturnTheObject() {
List<Product> redProducts = productRepository.findByAttribute("color", "red");
assertEquals(1, redProducts.size());
assertEquals("Laptop", redProducts.get(0).getName());
}
@Test
void whenFindByNestedAttribute_thenReturnTheObject() {
List<Product> electronicProducts = productRepository.findByNestedAttribute("details", "category", "electronics");
assertEquals(1, electronicProducts.size());
assertEquals("Headphones", electronicProducts.get(0)
.getName());
}
@Test
void whenFindByJsonPath_thenReturnTheObject() {
List<Product> redProducts = productRepository.findByJsonPath("color", "red");
assertEquals(1, redProducts.size());
assertEquals("Laptop", redProducts.get(0)
.getName());
}
@Test
void givenNestedJsonAttribute_whenFindByJsonPath_thenReturnTheObject() {
List<Product> electronicProducts = productRepository.findByNestedJsonPath("details", "category", "electronics");
assertEquals(1, electronicProducts.size());
assertEquals("Headphones", electronicProducts.get(0)
.getName());
}
@Test
void whenUsingJPASpecification_thenReturnTheObject() {
ProductSpecification spec = new ProductSpecification("color", "red");
Page<Product> redProducts = productRepository.findAll(spec, Pageable.unpaged());
assertEquals(1, redProducts.getContent()
.size());
assertEquals("Laptop", redProducts.getContent()
.get(0)
.getName());
}
}
@@ -0,0 +1,10 @@
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
@@ -0,0 +1,13 @@
DELETE FROM product;
INSERT INTO product (name, attributes)
VALUES ('Laptop', '{"color": "red", "size": "15 inch"}');
INSERT INTO product (name, attributes)
VALUES ('Phone', '{"color": "blue", "size": "6 inch"}');
INSERT INTO product (name, attributes)
VALUES ('Headphones', '{"brand": "Sony", "details": {"category": "electronics", "model": "WH-1000XM4"}}');
INSERT INTO product (name, attributes)
VALUES ('Laptop', '{"brand": "Dell", "details": {"category": "computers", "model": "XPS 13"}}');
@@ -0,0 +1,3 @@
DROP SEQUENCE IF EXISTS my_sequence_name;
CREATE SEQUENCE my_sequence_name START 1;
@@ -7,4 +7,6 @@
- [Difference Between JPA and Spring Data JPA](https://www.baeldung.com/spring-data-jpa-vs-jpa)
- [Differences Between Spring Data JPA findFirst() and findTop()](https://www.baeldung.com/spring-data-jpa-findfirst-vs-findtop)
- [Difference Between findBy and findAllBy in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-find-by-vs-find-all-by)
- [Calling Stored Procedures from Spring Data JPA Repositories](https://www.baeldung.com/spring-data-jpa-stored-procedures)
- More articles: [[<-- prev]](../spring-data-jpa-repo)
@@ -1,4 +1,4 @@
package com.baeldung.storedprocedure;
package com.baeldung.spring.data.persistence.storedprocedure;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -1,14 +1,13 @@
package com.baeldung.storedprocedure.controller;
import java.util.List;
package com.baeldung.spring.data.persistence.storedprocedure.controller;
import com.baeldung.spring.data.persistence.storedprocedure.entity.Car;
import com.baeldung.spring.data.persistence.storedprocedure.service.CarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baeldung.storedprocedure.entity.Car;
import com.baeldung.storedprocedure.service.CarService;
import java.util.List;
@RestController
public class CarController {
@@ -1,4 +1,4 @@
package com.baeldung.storedprocedure.entity;
package com.baeldung.spring.data.persistence.storedprocedure.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@@ -1,14 +1,13 @@
package com.baeldung.storedprocedure.repository;
import java.util.List;
package com.baeldung.spring.data.persistence.storedprocedure.repository;
import com.baeldung.spring.data.persistence.storedprocedure.entity.Car;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.baeldung.storedprocedure.entity.Car;
import java.util.List;
@Repository
public interface CarRepository extends JpaRepository<Car, Integer> {
@@ -1,12 +1,11 @@
package com.baeldung.storedprocedure.service;
import java.util.List;
package com.baeldung.spring.data.persistence.storedprocedure.service;
import com.baeldung.spring.data.persistence.storedprocedure.entity.Car;
import com.baeldung.spring.data.persistence.storedprocedure.repository.CarRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baeldung.storedprocedure.entity.Car;
import com.baeldung.storedprocedure.repository.CarRepository;
import java.util.List;
@Service
public class CarService {
@@ -0,0 +1,52 @@
package com.baeldung.spring.data.jpa.joinquery;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableAutoConfiguration
public class AppConfig {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
.build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
emf.setPackagesToScan("com.baeldung.spring.data.jpa.joinquery.entities"
, "com.baeldung.spring.data.jpa.joinquery.DTO"
, "com.baeldung.spring.data.jpa.joinquery.repositories");
emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
emf.setJpaProperties(getHibernateProperties());
return emf;
}
@Bean
public JpaTransactionManager transactionManager(LocalContainerEntityManagerFactoryBean entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory.getObject());
}
private Properties getHibernateProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
return properties;
}
}
@@ -0,0 +1,119 @@
package com.baeldung.spring.data.jpa.joinquery.DTO;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import org.springframework.context.annotation.Bean;
import java.time.LocalDate;
class DTO {
private Long customer_id;
private Long order_id;
private Long product_id;
public DTO(Long customer_id, Long order_id, Long product_id) {
this.customer_id = customer_id;
this.order_id = order_id;
this.product_id = product_id;
}
}
@Entity
@IdClass(DTO.class)
public class ResultDTO {
@Id
private Long customer_id;
@Id
private Long order_id;
@Id
private Long product_id;
public void setCustomer_id(Long customer_id) {
this.customer_id = customer_id;
}
public Long getProduct_id() {
return product_id;
}
public void setProduct_id(Long product_id) {
this.product_id = product_id;
}
public ResultDTO(Long customer_id, Long order_id, Long product_id, String customerName, String customerEmail, LocalDate orderDate, String productName, Double productPrice) {
this.customer_id = customer_id;
this.order_id = order_id;
this.product_id = product_id;
this.customerName = customerName;
this.customerEmail = customerEmail;
this.orderDate = orderDate;
this.productName = productName;
this.productPrice = productPrice;
}
private String customerName;
private String customerEmail;
private LocalDate orderDate;
private String productName;
private Double productPrice;
public Long getCustomer_id() {
return customer_id;
}
public void setCustoemr_id(Long custoemr_id) {
this.customer_id = custoemr_id;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getCustomerEmail() {
return customerEmail;
}
public void setCustomerEmail(String customerEmail) {
this.customerEmail = customerEmail;
}
public Long getOrder_id() {
return order_id;
}
public void setOrder_id(Long order_id) {
this.order_id = order_id;
}
public LocalDate getOrderDate() {
return orderDate;
}
public void setOrderDate(LocalDate orderDate) {
this.orderDate = orderDate;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Double getProductPrice() {
return productPrice;
}
public void setProductPrice(Double productPrice) {
this.productPrice = productPrice;
}
}
@@ -0,0 +1,66 @@
package com.baeldung.spring.data.jpa.joinquery.DTO;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import java.time.LocalDate;
//@Entity
//@IdClass(DTO.class)
public class ResultDTO_wo_Ids {
public ResultDTO_wo_Ids(String customerName, String customerEmail, LocalDate orderDate, String productName, Double productPrice) {
this.customerName = customerName;
this.customerEmail = customerEmail;
this.orderDate = orderDate;
this.productName = productName;
this.productPrice = productPrice;
}
private String customerName;
private String customerEmail;
private LocalDate orderDate;
private String productName;
private Double productPrice;
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getCustomerEmail() {
return customerEmail;
}
public void setCustomerEmail(String customerEmail) {
this.customerEmail = customerEmail;
}
public LocalDate getOrderDate() {
return orderDate;
}
public void setOrderDate(LocalDate orderDate) {
this.orderDate = orderDate;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Double getProductPrice() {
return productPrice;
}
public void setProductPrice(Double productPrice) {
this.productPrice = productPrice;
}
}
@@ -0,0 +1,104 @@
package com.baeldung.spring.data.jpa.joinquery.entities;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.util.Objects;
import java.util.Set;
@Entity
public class Customer {
public Customer(){}
@Id
//@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "customer"
, cascade = CascadeType.ALL)
private Set<CustomerOrder> customerOrders;
public Customer(Long id, Set<CustomerOrder> customerOrders, String email, LocalDate dob, String name) {
this.id = id;
this.customerOrders = customerOrders;
this.email = email;
this.dob = dob;
this.name = name;
}
public void setId(Long id) {
this.id = id;
}
public void setCustomerOrders(Set<CustomerOrder> customerOrders) {
this.customerOrders = customerOrders;
}
@Override
public String toString() {
return "Patient{" +
"id=" + id +
", orders=" + customerOrders +
", email='" + email + '\'' +
", dob=" + dob +
", name='" + name + '\'' +
'}';
}
public Set<CustomerOrder> getOrders() {
return customerOrders;
}
public void setOrders(Set<CustomerOrder> orders) {
this.customerOrders = orders;
}
@Column
private String email;
@Column(name = "dob", columnDefinition = "DATE")
private LocalDate dob;
@Column
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer patient = (Customer) o;
return Objects.equals(id, patient.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public Long getId() {
return id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public LocalDate getDob() {
return dob;
}
public void setDob(LocalDate dob) {
this.dob = dob;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,88 @@
package com.baeldung.spring.data.jpa.joinquery.entities;
import jakarta.persistence.*;
import java.time.LocalDate;
import java.util.Objects;
import java.util.Set;
@Entity
public class CustomerOrder {
public CustomerOrder(){}
@Id
//@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public void setId(Long id) {
this.id = id;
}
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
@OneToMany(mappedBy = "customerOrder"
, cascade = CascadeType.ALL)
private Set<Product> products;
@Column
private LocalDate orderDate;
public CustomerOrder(Long id, Set<Product> products, LocalDate orderDate, Customer customer) {
this.id = id;
this.products = products;
this.orderDate = orderDate;
this.customer = customer;
}
@Override
public String toString() {
return "Consult{" +
"id=" + id +
", products=" + products +
", orderDate=" + orderDate +
", customer=" + customer +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomerOrder co = (CustomerOrder) o;
return Objects.equals(id, co.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="customer_id", nullable = false)
private Customer customer;
public Long getId() {
return id;
}
public LocalDate getOrderDate() {
return orderDate;
}
public void setOrderDate(LocalDate orderDate) {
this.orderDate = orderDate;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
@@ -0,0 +1,84 @@
package com.baeldung.spring.data.jpa.joinquery.entities;
import jakarta.persistence.*;
import java.util.Objects;
@Entity
public class Product {
public Product(){}
@Id
//@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public Product(Long id, String productName, Double price, CustomerOrder customerOrder) {
this.id = id;
this.productName = productName;
this.price = price;
this.customerOrder = customerOrder;
}
@Column
private String productName;
@Column
private Double price;
@Override
public String toString() {
return "Dispense{" +
"id=" + id +
", productName='" + productName + '\'' +
", price=" + price +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product dispense = (Product) o;
return Objects.equals(id, dispense.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public CustomerOrder getCustomerOrder() {
return customerOrder;
}
public void setCustomerOrder(CustomerOrder co) {
this.customerOrder = co;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="customerorder_id", nullable = false)
private CustomerOrder customerOrder;
}
@@ -0,0 +1,9 @@
package com.baeldung.spring.data.jpa.joinquery.repositories;
import com.baeldung.spring.data.jpa.joinquery.entities.Customer;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {
}
@@ -0,0 +1,34 @@
package com.baeldung.spring.data.jpa.joinquery.repositories;
import com.baeldung.spring.data.jpa.joinquery.DTO.ResultDTO;
import com.baeldung.spring.data.jpa.joinquery.DTO.ResultDTO_wo_Ids;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
@Repository
public interface JoinRepository extends CrudRepository<ResultDTO, Long> {
@Query(value = "SELECT new com.baeldung.spring.data.jpa.joinquery.DTO.ResultDTO(c.id, o.id, p.id, c.name, c.email, o.orderDate, p.productName, p.price) "
+ " from Customer c, CustomerOrder o ,Product p "
+ " where c.id=o.customer.id "
+ " and o.id=p.customerOrder.id "
+ " and c.id=?1 ")
List<ResultDTO> findResultDTOByCustomer(Long id);
@Query(value = "SELECT new com.baeldung.spring.data.jpa.joinquery.DTO.ResultDTO_wo_Ids(c.name, c.email, o.orderDate, p.productName, p.price) "
+ " from Customer c, CustomerOrder o ,Product p "
+ " where c.id=o.customer.id "
+ " and o.id=p.customerOrder.id "
+ " and c.id=?1 ")
List<ResultDTO_wo_Ids> findResultDTOByCustomerWithoutIds(Long id);
@Query(value = "SELECT c.*, o.*, p.* "
+ " from Customer c, CustomerOrder o ,Product p "
+ " where c.id=o.customer_id "
+ " and o.id=p.customerOrder_id "
+ " and c.id=?1 "
, nativeQuery = true)
List<Map<String, Object>> findByCustomer(Long id);
}
@@ -0,0 +1,106 @@
package com.baeldung.spring.data.jpa.joinquery;
import com.baeldung.spring.data.jpa.joinquery.DTO.ResultDTO_wo_Ids;
import com.baeldung.spring.data.jpa.joinquery.entities.Customer;
import com.baeldung.spring.data.jpa.joinquery.entities.CustomerOrder;
import com.baeldung.spring.data.jpa.joinquery.DTO.ResultDTO;
import com.baeldung.spring.data.jpa.joinquery.entities.Product;
import com.baeldung.spring.data.jpa.joinquery.repositories.CustomerRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.PersistenceUnit;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.baeldung.spring.data.jpa.joinquery.repositories.JoinRepository;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = { AppConfig.class })
class JoinRepositoryUnitTest {
@Autowired
JoinRepository joinRepository;
@Autowired
CustomerRepository customerRepository;
@PersistenceUnit
EntityManagerFactory entityManagerFactory;
EntityManager entityManager;
@BeforeEach
void setUp() {
customerRepository.deleteAll();
entityManager = entityManagerFactory.createEntityManager();
Customer c = new Customer(1L, null, "email1@email.com", LocalDate.now(), "Customer");
CustomerOrder o1 = new CustomerOrder(1L, null, LocalDate.now(), c);
CustomerOrder o2 = new CustomerOrder(2L, null, LocalDate.of(2024,1,1), c);
Product p1 = new Product(1L,"Product1", 25.20, o1);
Product p2 = new Product(2L, "Product2", 26.20, o1);
Product p3 = new Product(3L, "Product3", 27.20, o2);
Set<CustomerOrder> cos01 = new HashSet<>();
cos01.add(o1);
cos01.add(o2);
Set<Product> productsO1 = new HashSet<>();
productsO1.add(p1);
productsO1.add(p2);
Set<Product> productsO2 = new HashSet<>();
productsO1.add(p3);
c.setCustomerOrders(cos01);
o1.setProducts(productsO1);
o2.setProducts(productsO2);
EntityTransaction et = getTransaction();
entityManager.persist(c);
entityManager.flush();
et.commit();
}
@AfterEach
void tearDown() {
}
@Test
void whenFindResultDTOByCustomer_thenReturnResultDTO() {
List<ResultDTO> resultDTO = joinRepository.findResultDTOByCustomer(1L);
assertInstanceOf(ResultDTO.class, resultDTO.get(0));
}
@Test
void whenFindByCustomerNativeQuery_thenReturnMapsForObjects() {
List<Map<String, Object>> res = joinRepository.findByCustomer(1L);
//the map objects in the res List has 9 String keys aka 9 columns corresponding to the columns of customer, customerOrder, product
res.forEach(map -> {
assertEquals(9, map.keySet().size());
});
}
@Test
void whenFindResultDTOByCustomerWithoutIds_thenReturnResultDTO() {
List<ResultDTO_wo_Ids> resultDTO = joinRepository.findResultDTOByCustomerWithoutIds(1L);
assertInstanceOf(ResultDTO_wo_Ids.class, resultDTO.get(0));
}
private EntityTransaction getTransaction() {
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
return transaction;
}
}
@@ -8,7 +8,6 @@ This module contains articles about repositories in Spring Data JPA
- [Spring Data JPA Adding a Method in All Repositories](https://www.baeldung.com/spring-data-jpa-method-in-all-repositories)
- [Spring Data Composable Repositories](https://www.baeldung.com/spring-data-composable-repositories)
- [Spring Data JPA Repository Populators](https://www.baeldung.com/spring-data-jpa-repository-populators)
- [Calling Stored Procedures from Spring Data JPA Repositories](https://www.baeldung.com/spring-data-jpa-stored-procedures)
- [LIKE Queries in Spring JPA Repositories](https://www.baeldung.com/spring-jpa-like-queries)
- More articles: [[--> next]](../spring-data-jpa-repo-2)
@@ -6,8 +6,8 @@ import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@EnableJpaRepositories("com.baeldung.jpa.modifying")
@EntityScan("com.baeldung.jpa.modifying")
@EnableJpaRepositories("com.baeldung.jpa.modifying.repository")
@EntityScan("com.baeldung.jpa.modifying.model")
public class ModifyingApplication {
public static void main(String[] args) {
@@ -78,9 +78,7 @@ public class Possession {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Possesion [id=").append(id).append(", name=").append(name).append("]");
return builder.toString();
return "Possession [id=" + id + ", name=" + name + "]";
}
}
@@ -96,9 +96,7 @@ public class User {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("User [name=").append(name).append(", id=").append(id).append("]");
return builder.toString();
return "User [name=" + name + ", id=" + id + "]";
}
@Override
@@ -1,4 +1,4 @@
package com.baeldung.jpa.modifying.dao;
package com.baeldung.jpa.modifying.repository;
import java.time.LocalDate;
import java.util.List;
@@ -1,4 +1,4 @@
package com.baeldung.jpa.query;
package com.baeldung.jpa.query.model;
import java.time.LocalDate;
import java.util.Objects;
@@ -106,9 +106,7 @@ public class User {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("User [name=").append(name).append(", id=").append(id).append("]");
return builder.toString();
return "User [name=" + name + ", id=" + id + "]";
}
@Override
@@ -1,4 +1,4 @@
package com.baeldung.jpa.query;
package com.baeldung.jpa.query.repository;
import java.util.Collection;
import java.util.List;
@@ -12,6 +12,8 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.baeldung.jpa.query.model.User;
@Repository
public interface UserRepository extends JpaRepository<User, Integer>, UserRepositoryCustom {
@Query("SELECT u FROM User u WHERE u.status = 1")
@@ -1,10 +1,12 @@
package com.baeldung.jpa.query;
package com.baeldung.jpa.query.repository;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import com.baeldung.jpa.query.model.User;
public interface UserRepositoryCustom {
List<User> findUserByEmails(Set<String> emails);
@@ -1,4 +1,4 @@
package com.baeldung.jpa.query;
package com.baeldung.jpa.query.repository;
import java.util.ArrayList;
import java.util.Collection;
@@ -7,6 +7,8 @@ import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.baeldung.jpa.query.model.User;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
@@ -32,7 +32,7 @@ public class PersistenceConfig {
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("com.baeldung.jpa.simple.entity");
em.setPackagesToScan("com.baeldung.jpa.simple.model");
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
@@ -1,4 +1,4 @@
package com.baeldung.jpa.simple.entity;
package com.baeldung.jpa.simple.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
@@ -1,4 +1,4 @@
package com.baeldung.jpa.simple.entity;
package com.baeldung.jpa.simple.model;
import java.io.Serializable;
@@ -1,4 +1,4 @@
package com.baeldung.jpa.simple.entity;
package com.baeldung.jpa.simple.model;
import java.time.ZonedDateTime;
@@ -5,7 +5,7 @@ import java.util.List;
import org.springframework.data.repository.ListCrudRepository;
import org.springframework.stereotype.Repository;
import com.baeldung.jpa.simple.entity.Book;
import com.baeldung.jpa.simple.model.Book;
@Repository
public interface BookListRepository extends ListCrudRepository<Book, Long> {
@@ -7,7 +7,7 @@ import org.springframework.data.repository.ListCrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import com.baeldung.jpa.simple.entity.Book;
import com.baeldung.jpa.simple.model.Book;
@Repository
public interface BookPagingAndSortingRepository extends PagingAndSortingRepository<Book, Long>, ListCrudRepository<Book, Long> {

Some files were not shown because too many files have changed in this diff Show More