Merge pull request #16279 from zeesh49/BAEL-7692-Join-Queries

Bael 7692 join queries
This commit is contained in:
Maiklins 2024-04-07 22:39:28 +02:00 committed by GitHub
commit f8fe72540d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 662 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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> {
}

View File

@ -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);
}

View File

@ -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;
}
}