Jacobvu84 / developer-career

Study for interview
1 stars 0 forks source link

Day 01.03 Tìm hiểu JpaRepository<T, id> #6

Open Jacobvu84 opened 2 years ago

Jacobvu84 commented 2 years ago

Repository là nơi chứa dữ liệu, dữ liệu sẽ được lấy ra từ đây để xử lý, nó chứa sẵn các hàm xử lý data như findAll, FindByXXXX, CRUD.... mà không cần phải viết lại. (Lợi của dùng framework là vậy. ko cần phải viết lại mọi thứ từ đầu)

package jacob.vu.coffee.repositories;

import jacob.vu.coffee.models.Product;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {

}
Jacobvu84 commented 2 years ago

@Autowired đây là một DI = Dependency Injection. Giúp khởi tạo một đối tượng ngay từ khi application bắt đầu và sử dụng nó cho cả chương trình. Giống với khái niệm Singleton pattern

package jacob.vu.coffee.controllers;
....

@RestController
@RequestMapping(path = "/api/v1/products")
public class ProductController {

    @GetMapping("")
    List<Product> getAllProducts(){

        return List.of(
                new Product(1L, "Iphone 14", 2022, 800.0, ""),
                new Product(2L, "VSmart Pro", 2021, 900.0, ""));
    }
}

Mới


@RestController
@RequestMapping(path = "/api/v1/products")
public class ProductController {

    @Autowired
    ProductRepository repository;

    @GetMapping("")
    List<Product> getAllProducts(){

        return repository.findAll();
    }
}

Vậy repository.findAll(); sẽ lấy dữ liệu ở đâu ?

Jacobvu84 commented 2 years ago

@Configuration class nào sử dụng annotation này thì bên trong sẽ chứa những Bean method những bean methods này sẽ được gọi ngay khi application run.

Chúng ta có thể dụng những @Bean này để khởi tạo database, biến môi trường.

package jacob.vu.coffee.database;

import jacob.vu.coffee.models.Product;
import jacob.vu.coffee.repositories.ProductRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Database {

    private static final Logger logger = LoggerFactory.getLogger(Database.class);

    @Bean
    CommandLineRunner initDatabase(ProductRepository productRepository){
        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                Product productA = new Product(1L, "Iphone 14", 2022, 800.0, "");
                Product productB = new Product(2L, "VSmart Pro", 2021, 900.0, "");
                logger.info("insert database" + productRepository.save(productA));
                logger.info("insert database" + productRepository.save(productB));
            }
        };
    }
}
Jacobvu84 commented 2 years ago

[Issue]

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'productController': Unsatisfied dependency expressed through field 'repository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'productRepository' defined in jacob.vu.coffee.repositories.ProductRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class jacob.vu.coffee.models.Product

Not a managed type: class jacob.vu.coffee.models.Product Lỗi liên quan đến Jpa. Khi @Bean hoạt động thì nó không tìm thấy thực thể Product.

[Fix] Sử dụng @Entity cho Product class

Khi sử dụng @Entity thì nó yêu cầu Product phải có primary key. Ta cần phải chọn một trường làm khóa chính cho entity này. Sử dụng @Id để đánh chọn.

Nếu muốn giá trị id tự động tăng thì dùng @GeneratedValue(strategy = GenerationType.AUTO)

...
@Entity
public class Product {

    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    private Long id;
    private String productName;
    private int year;
.....
Jacobvu84 commented 2 years ago

[Issue]

GenerationTarget encountered exception accepting command : Error executing DDL "create table product (product_id bigint not null, price double, product_name varchar(255), url varchar(255), year integer not null, primary key (product_id))" via JDBC Statement

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table product (product_id bigint not null, price double, product_name varchar(255), url varchar(255), [*]year integer not null, primary key (product_id))"; expected "identifier"; SQL statement: create table product (product_id bigint not null, price double, product_name varchar(255), url varchar(255), year integer not null, primary key (product_id)) [42001-214]

[Fix] Do trong Entity có chứa từ khóa của SQL

Tham khảo ở đây.

In my case, the attribute year is reserved word for SQL

reserved for: dành riêng cho. Giữ chỗ

Jacobvu84 commented 2 years ago

@Entity : This tells Hibernate to make a table out of this class