javaspring将带有外键的数据从@requestbody插入db

kpbpu008  于 2021-07-13  发布在  Java
关注(0)|答案(1)|浏览(234)

我想将从@requestbody获得的数据插入mariadb数据库。目前我可以存储数据没有外键没有任何问题,但现在我需要存储外键,我不知道如何做到这一点。
我的实体现在是这样的:
超类:

package webtoolbackend.Model.Superclass;

import webtoolbackend.Model.Reference.Reference_Category;

import javax.persistence.*;

@MappedSuperclass
public abstract class Category {
private long category_ID;
private String title;
private String description;

public Category() {

}

public Category(long category_ID, String title, String description) {
    this.category_ID = category_ID;
    this.title = title;
    this.description = description;
}

public Category(String title, String description) {
    this.title = title;
    this.description = description;
}

@Id
@Column(name ="Category_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
public long getCategory_ID() {
    return category_ID;
}

public void setCategory_ID(long category_ID) {
    this.category_ID = category_ID;
}

@Column(name ="Title")
public String getTitle() {
    return title;
}

public void setTitle(String title) {
    this.title = title;
}

@Column(name ="Description")
public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}
}

类别:

package webtoolbackend.Model.DE;

import webtoolbackend.Model.Reference.Reference_Category;
import webtoolbackend.Model.Superclass.Category;

import javax.persistence.*;
import java.util.Set;

@Entity
@Table(name="Category_DE")
public class Category_DE extends Category {
private Sector_DE sector_de;
private Set<Question_DE> questions_de;
private Set<Reference_Category> reference_categories;
private long sector_id;

public Category_DE() {
    super();
}

public Category_DE(long category_ID, String title, String description) {
    super(category_ID, title, description);
}
public Category_DE(String title, String description, Sector_DE sector_de) {
    super(title, description);
    this.sector_de = sector_de;
}

public Category_DE(String title, String description, long sector_id) {
    super(title, description);
    this.sector_id = sector_id;
}

@ManyToOne
@JoinColumn(name="Sector_IDFS")
public Sector_DE getSector_de(){
    return sector_de;
}

public void setSector_de(Sector_DE sector_de) {
    this.sector_de = sector_de;
}

@OneToMany(mappedBy="category_de", cascade=CascadeType.ALL)
public Set<Question_DE> getQuestions_de() {
    return questions_de;
}

public void setQuestions_de(Set<Question_DE> questions_de) {
    this.questions_de = questions_de;
}

@OneToMany(mappedBy="category_de", cascade = CascadeType.ALL)
public Set<Reference_Category> getReference_categories() {
    return reference_categories;
}

public void setReference_categories(Set<Reference_Category> reference_categories) {
    this.reference_categories = reference_categories;
}
}

我的控制器:

@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/api")
public class Category_Controller {
@Autowired
Category_Repository category_repository;

@PostMapping("/category-de")
public ResponseEntity<Category> createCategory(@RequestBody Category_DE category_de) {
    try{
        Category_DE savedCategory = category_repository
                .save(new Category_DE(category_de.getTitle(), category_de.getDescription(), category_de.getSector_de()));
        return new ResponseEntity<>(savedCategory, HttpStatus.CREATED);
    }
    catch (Exception e){
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
}

来自requestbody的我的json:

{
"title": "test",
"description": "testDesc",
"sector_de": {
    "sector_id": 1,
    "title": "test"
}
}
wydwbb8l

wydwbb8l1#

因为您使用的实体对象与 @RequestBody ,您需要考虑一些事情来将它们保存到数据库中。让我们逐一看看

当类别和扇区都是新对象时1

当您希望api每次都创建新的对象时,这种方法就会起作用,因为使用Map通过jpa将更改级联到子表是很容易的。假设你的要求是这样的

{
   "title": "test",
   "description": "testDesc",
   "sector_de": {
     "title": "test"
   }
}

这里两个对象(主对象和内部对象)都缺少 id 字段,所以直接将其保存到数据库是安全的,如果我们在父表上使用它,两个表都将接收条目。因为,json将被序列化为 Category 对象,如果已定义setter,则它也将具有父对象 Sector_DE 对象已初始化。

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name="Sector_IDFS")
public Sector_DE getSector_de(){
    return sector_de;
}

所以,spring-jpa将拯救 Category 对象和原因 cascade 它还将拯救世界 Sector_DE 对象也是。你的要求是不类似于这个,所以这将不适用于这个案件,但我提到它,因为这个信息将在您的情况下有用。

当类别为新且扇区存在时(您的案例)

现在,你的请求 sector_id 假如

{
   "title": "test",
   "description": "testDesc",
   "sector_de": {
     "sector_id" : 1,
     "title": "test"
   }
}

所以你的 Category 请求对象将具有 Sector_DE 对象初始化为 sector_id 字段,如果您试图按照上面的代码直接保存它,spring data jpa可能会给您提供有关分离对象的错误。
原因是,持久性上下文可能已经有了该对象,并且由于您的对象是从外部创建的,而不是从存储库中获取的,所以持久性上下文不知道它。如果没有任何扇区具有相同的 id 在数据库中。
因此,这是一种更新请求,您正在更新/向现有扇区添加类别,因此需要从数据库中获取相关对象 sector_id .
在这种情况下,您必须首先检查是否有一个扇区具有相同的 id ,要做到这一点,您需要 SectorRepository 类似于 CategoryRepostiory 那你就这样检查

public ResponseEntity<Category> createCategory(@RequestBody Category_DE category_de) {
    try{
           //assuming SectorRepository available to this function
           Sector_DE sector = 
                 sectorRepository.findById(category_de.getSector().getSectorId())
                                 .orElseThrow(() -> new IllegalArgumentException());

            category_de.setSector_de(sector); //Important! will save foriegn key to table
            Category_DE savedCategory = category_repository
                .save(new Category_DE(category_de.getTitle(), category_de.getDescription(), category_de.getSector_de()));
        return new ResponseEntity<>(savedCategory, HttpStatus.CREATED);
    }
    catch (Exception e){
        return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

因为我们在这里操作child,所以不需要将更改级联到parent,除非您也要更新parent(sector\u de)的某些属性,因此,您现有的Map就可以了。

@ManyToOne
@JoinColumn(name="Sector_IDFS")
public Sector_DE getSector_de(){
    return sector_de;
}

脚注

1尽管我提到了第一种情况,说明了在两个对象都是新对象的情况下Map是如何工作的,但通常我们不会从子对象侧创建新对象,这种方法应该始终先保存父对象,然后再将子对象添加到其中。所以这是一个两步的过程,应该避免从子级到父级的级联更改。

相关问题