BAEL-7572: Spring Data JPA Repository for Database View (#15918)
This commit is contained in:
parent
7039de679d
commit
6d1ed25da1
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DatabaseViewApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DatabaseViewApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import jakarta.persistence.AttributeOverride;
|
||||
import jakarta.persistence.AttributeOverrides;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.EmbeddedId;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "SHOP_SALE_VIEW")
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(of = {"id"})
|
||||
public class ShopSale {
|
||||
|
||||
@EmbeddedId
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride( name = "shopId", column = @Column(name = "shop_id")),
|
||||
@AttributeOverride( name = "year", column = @Column(name = "transaction_year")),
|
||||
@AttributeOverride( name = "month", column = @Column(name = "transaction_month"))
|
||||
})
|
||||
private ShopSaleCompositeId id;
|
||||
|
||||
@Column(name = "shop_location", length = 100)
|
||||
private String shopLocation;
|
||||
|
||||
@Column(name = "total_amount")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode
|
||||
public class ShopSaleCompositeId {
|
||||
|
||||
private int shopId;
|
||||
|
||||
private int year;
|
||||
|
||||
private int month;
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ShopSaleRepository extends ViewRepository<ShopSale, ShopSaleCompositeId> {
|
||||
|
||||
List<ShopSale> findByIdShopId(Integer shopId);
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Entity
|
||||
@Table(name = "SHOP_SALE_VIEW")
|
||||
@Getter
|
||||
@Builder
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@EqualsAndHashCode(of = {"id"})
|
||||
public class ShopSaleVid {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
private Long id;
|
||||
|
||||
@Column(name = "shop_id")
|
||||
private int shopId;
|
||||
|
||||
@Column(name = "shop_location", length = 100)
|
||||
private String shopLocation;
|
||||
|
||||
@Column(name = "transaction_year")
|
||||
private int year;
|
||||
|
||||
@Column(name = "transaction_month")
|
||||
private int month;
|
||||
|
||||
@Column(name = "total_amount")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ShopSaleVidRepository extends ViewNoIdRepository<ShopSaleVid, Long> {
|
||||
|
||||
List<ShopSaleVid> findByShopId(Integer shopId);
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@NoRepositoryBean
|
||||
public interface ViewNoIdRepository<T, K> extends Repository<T, K> {
|
||||
|
||||
long count();
|
||||
|
||||
List<T> findAll();
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.repository.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@NoRepositoryBean
|
||||
public interface ViewRepository<T, K> extends Repository<T, K> {
|
||||
|
||||
long count();
|
||||
|
||||
boolean existsById(K id);
|
||||
|
||||
List<T> findAll();
|
||||
|
||||
List<T> findAllById(Iterable<K> ids);
|
||||
|
||||
Optional<T> findById(K id);
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(classes = DatabaseViewApplication.class, properties = {
|
||||
"spring.jpa.show-sql=true",
|
||||
"spring.jpa.properties.hibernate.format_sql=true",
|
||||
"spring.jpa.hibernate.ddl-auto=none",
|
||||
"spring.jpa.defer-datasource-initialization=true",
|
||||
"spring.sql.init.data-locations=classpath:shop-sale-data.sql"
|
||||
})
|
||||
class ShopSaleRepositoryIntegrationTest {
|
||||
|
||||
private static final ShopSaleCompositeId id = ShopSaleCompositeId.builder()
|
||||
.shopId(1)
|
||||
.year(2024)
|
||||
.month(1)
|
||||
.build();
|
||||
|
||||
@Autowired
|
||||
private ShopSaleRepository shopSaleRepository;
|
||||
|
||||
@Test
|
||||
void whenCount_thenValueGreaterThanOne() {
|
||||
assertThat(shopSaleRepository.count()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenFindAll_thenReturnAllRecords() {
|
||||
assertThat(shopSaleRepository.findAll()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenExistsById_thenReturnTrue() {
|
||||
assertThat(shopSaleRepository.existsById(id)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenFindAllById_thenReturnListWithTwoInstances() {
|
||||
assertThat(shopSaleRepository.findAllById(List.of (id))).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenFindById_thenReturnAnInstance() {
|
||||
assertThat(shopSaleRepository.findById(id).isPresent()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenFindByShopId_thenReturnAllShopSaleOfThatShop() {
|
||||
var shopId = 1;
|
||||
List<ShopSale> shopSaleVidList = shopSaleRepository.findByIdShopId(shopId);
|
||||
assertThat(shopSaleVidList).isNotEmpty();
|
||||
shopSaleVidList.forEach(s -> assertThat(s.getId().getShopId()).isEqualTo(shopId));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.dbview;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(classes = DatabaseViewApplication.class, properties = {
|
||||
"spring.jpa.show-sql=true",
|
||||
"spring.jpa.properties.hibernate.format_sql=true",
|
||||
"spring.jpa.hibernate.ddl-auto=none",
|
||||
"spring.jpa.defer-datasource-initialization=true",
|
||||
"spring.sql.init.data-locations=classpath:shop-sale-data.sql"
|
||||
})
|
||||
class ShopSaleVidRepositoryIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private ShopSaleVidRepository shopSaleVidRepository;
|
||||
|
||||
@Test
|
||||
void whenCount_thenValueGreaterThanOne() {
|
||||
assertThat(shopSaleVidRepository.count()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenFindAll_thenReturnAllRecords() {
|
||||
assertThat(shopSaleVidRepository.findAll()).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenFindByShopId_thenReturnAllShopSaleOfThatShop() {
|
||||
var shopId = 1;
|
||||
List<ShopSaleVid> shopSaleList = shopSaleVidRepository.findByShopId(shopId);
|
||||
assertThat(shopSaleList).isNotEmpty();
|
||||
shopSaleList.forEach(s -> assertThat(s.getShopId()).isEqualTo(shopId));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
CREATE TABLE SHOP
|
||||
(
|
||||
shop_id int AUTO_INCREMENT,
|
||||
shop_location varchar(100) NOT NULL UNIQUE,
|
||||
PRIMARY KEY(shop_id)
|
||||
);
|
||||
|
||||
|
||||
CREATE TABLE SHOP_TRANSACTION
|
||||
(
|
||||
transaction_id bigint AUTO_INCREMENT,
|
||||
transaction_date date NOT NULL,
|
||||
shop_id int NOT NULL,
|
||||
amount decimal(8,2) NOT NULL,
|
||||
PRIMARY KEY(transaction_id),
|
||||
FOREIGN KEY(shop_id) REFERENCES SHOP(shop_id)
|
||||
);
|
||||
|
||||
|
||||
CREATE VIEW SHOP_SALE_VIEW AS
|
||||
SELECT ROW_NUMBER() OVER () AS id, shop_id, shop_location, transaction_year, transaction_month, SUM(amount) AS total_amount
|
||||
FROM (
|
||||
SELECT shop.shop_id, shop.shop_location, trans.amount, YEAR(transaction_date) AS transaction_year, MONTH(transaction_date) AS transaction_month
|
||||
FROM SHOP shop, SHOP_TRANSACTION trans
|
||||
WHERE shop.shop_id = trans.shop_id
|
||||
) SHOP_MONTH_TRANSACTION
|
||||
GROUP BY shop_id, transaction_year, transaction_month;
|
||||
|
||||
|
||||
INSERT INTO SHOP(shop_location) VALUES ('Ealing');
|
||||
INSERT INTO SHOP(shop_location) VALUES ('Richmond');
|
||||
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-01-05', 1, 3.49);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-01-31', 1, 7.29);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-02-09', 1, 1.60);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-02-17', 1, 5.99);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-02-18', 1, 5.99);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-03-01', 1, 8.99);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-03-22', 1, 5.49);
|
||||
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-01-15', 2, 8.99);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-01-18', 2, 8.99);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-02-01', 2, 5.99);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-02-05', 2, 2.50);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-03-01', 2, 5.99);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-03-02', 2, 6.60);
|
||||
INSERT INTO SHOP_TRANSACTION(transaction_date, shop_id, amount) VALUES ('2024-03-17', 2, 1.19);
|
Loading…
Reference in New Issue