我是JPA和Spring的初学者。这也是我的第一个问题。所以,为我的错误感到抱歉。我正在从简单的场景开始练习。我有两个实体,分别是“产品”和“类别”,具有双向多对一/一对多关联。
类别:
@Entity
@Table(name = "categories")
@NoArgsConstructor
@AllArgsConstructor
@Data
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = Long.class)
public class Category implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "name", length = 50, nullable = false)
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
private List<Product> products = new ArrayList<Product>();
}
产品类别:
@Table(name = "products")
@NoArgsConstructor
@AllArgsConstructor
@Data
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = Long.class)
public class Product implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "title", nullable = false, length = 50)
private String title;
@Column(name = "price", precision = 4, scale = 2, nullable = false)
private Double price;
@Column(name = "quantity", nullable = false)
private int quantity;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id", foreignKey = @ForeignKey(name = "FK_product_category"))
private Category category;
}
CategoryRepository和ProductRepository均从JpaRepository实现。 带有@Query注释的方法签名很少。
使用带有@Autowired的存储库的服务。没有任何业务逻辑。
CategoryService类:
@Transactional
public class CategoryService implements IRepositoryService<Category, Long> {
private ICategoryRepository categoryRepository;
@Autowired
public CategoryService(ICategoryRepository categoryRepository) {
this.categoryRepository = categoryRepository;
}
@Override
public List<Category> findAllOrderById() {
return categoryRepository.findAllOrderById();
}
@Override
public Category findById(Long id) {
return categoryRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}
@Override
public List<Category> findByForeignKey(Long categoryId) {
return null;
}
@Override
public void add(Category category) {
category.getProducts().forEach(product -> product.setCategory(category));
categoryRepository.save(category);
}
@Override
public void update(Category category) {
categoryRepository.save(category);
}
@Override
public void deleteById(Long id) {
categoryRepository.deleteById(id);
}
ProductService类:
@Transactional
public class ProductService implements IRepositoryService<Product, Long>{
@Autowired
private IProductRepository productRepository;
@Override
public List<Product> findAllOrderById() {
return productRepository.findAllOrderById();
}
@Override
public Product findById(Long id) {
return productRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}
@Override
public List<Product> findByForeignKey(Long categoryId) {
return productRepository.findByCategoryId(categoryId);
}
@Override
public void add(Product entity) {
productRepository.save(entity);
}
@Override
public void update(Product entity) {
productRepository.save(entity);
}
@Override
public void deleteById(Long id) {
productRepository.deleteById(id);
}
}
最后,两个实体都有单独的restcontroller类。 我在Postman中添加了一个仅带有名称的类别,因此product为空(这部分是正常的)。但是,当我从Postman或其他前端应用程序添加产品时,未设置产品的类别(我在json中设置category_id)。但是在数据库中,产品表的category_id列值为null。 json string
我也有延迟获取类型和json问题的问题。但是主要问题首先出现。
谢谢您的帮助。
答案 0 :(得分:0)
只要您传递正确的json请求主体,上述JPA实体映射就应该起作用。另外,您可能需要使用@ JsonBackReference / @ JsonManagedReference以避免stackoverflow异常(有关更多信息,请参见JsonManagedReference vs JsonBackReference)
请求: POST:本地主机:/ cat
{ "name" :"Construction" }
POST:localhost:/ prod,这里我们使用类别ID =1。更改它以匹配“ Construction”类别的ID
{
"title" :"Bricks",
"price" :"1.2",
"quantity": "100",
"category": {
"id": 1
}
}
将此类添加到jpademo
包中并运行。
package jpademo;
import com.fasterxml.jackson.annotation.*;
import lombok.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.web.bind.annotation.*;
import javax.persistence.*;
import java.util.*;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@RestController
@RequiredArgsConstructor
class Ctrl {
final CategoryRepo categoryRepo;
final ProductRepo prodRepo;
@PostMapping("/cat")
void cat(@RequestBody Category cat) {
categoryRepo.save(cat);
}
@PostMapping("/prod")
void prod(@RequestBody Product p) {
prodRepo.save(p);
}
@GetMapping("/cat")
List<Category> cats() {
return categoryRepo.findAll();
}
@GetMapping("/prod")
List<Product> prods() {
return prodRepo.findAll();
}
}
interface CategoryRepo extends JpaRepository<Category, Long> {}
interface ProductRepo extends JpaRepository<Product, Long> {}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
@JsonManagedReference //to avoid Stackoverflow
private List<Product> products = new ArrayList<>();
}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private Double price;
private int quantity;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id", foreignKey = @ForeignKey(name = "FK_product_category"))
@JsonBackReference
private Category category;
}
答案 1 :(得分:0)
这是使用杰克逊数据类型模块的唯一配置。
@Configuration
public class JacksonConfig {
@Bean
public Hibernate5Module hibernate5Module() {
return new Hibernate5Module();
}
@Bean
public AfterburnerModule afterburnerModule() {
return new AfterburnerModule();
}
}
这样的响应: json response