Spring JPA - 如何使用复合键(EmbeddedID)保存对象

Ari*_*ane 5 java spring spring-data-jpa spring-boot

我正在构建一个 Spring 系统,其中涉及用户和他们正在服用的药物。我有一个包含表的数据库:用户,药物

我正在创建一个新的数据类型名称 UserMed,它由复合主键组成 - 药物的 ID 和用户的用户名(上表的主键)

以下是 UserMed 实体代码:

@Entity
@Table(name = "userMeds")
public class UserMed implements Serializable {

    @Id
    @EmbeddedId
    private UserMedId userMedId;


    public UserMed(int drugID, String username) {
        this.userMedId.drug_id = drugID;
        this.userMedId.username = username;

    }

    public UserMed() {
    }


    public String getUsername() {
        return this.userMedId.username;
    }

    public void setUsername(String username) {
        this.userMedId.username = username;
    }


}
Run Code Online (Sandbox Code Playgroud)

这是 EmbeddedID UserMedId 数据类型:

@RequiredArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@EqualsAndHashCode
@Embeddable
public class UserMedId implements Serializable {

    @NonNull
    public int drug_id;

    @NonNull
    public String username;
}
Run Code Online (Sandbox Code Playgroud)

我有一条路线,我的前端 POST 请求该路线。我仔细检查了前端,它正在使用序列化的 UserMed 类型执行 POST 请求,如下所示:

export class UserMed {
    constructor(
        public drug_id: number,
        public username: string,
    ) {
    }
}
Run Code Online (Sandbox Code Playgroud)

但是在请求正文中使用 userMed 类型命中路由会导致此错误:

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: null; nested exception is com.fasterxml.jackson.databind.JsonMappingException: N/A
 at [Source: (PushbackInputStream); line: 1, column: 28] (through reference chain: com.example.configbackendspring.entities.UserMed["username"])]
Run Code Online (Sandbox Code Playgroud)

这是命中的 POST 映射/路由

    @PostMapping("/addNewUserMed")
    public String addNewUser(@RequestBody UserMed userMed) {
        userMedService.addNewUserMed(userMed);
        return "success";
    }
Run Code Online (Sandbox Code Playgroud)

这是 addNewUserMed 方法:

   public void addNewUserMed(UserMed userMed) {
        userMedRepository.save(userMed);
    }

Run Code Online (Sandbox Code Playgroud)

我认为问题在于,由于它是使用的复合键,因此从前端发送的 UserMed 包含字段“username”和“drug_id”,但 Spring UserMed 数据类型具有复合键,因此只有字段“ userMedId.drug_id”和“userMedId.用户名”。

有人可以建议如何使保存操作正确工作吗?

谢谢

Meh*_*ami 0

您不能将您的实体用于控制器,而是必须创建与您的实体相对应的DTO并在控制器上使用它。

因此,在您的场景中,您必须首先创建 UserMedDto 和 UserMedIdDto 并在控制器中使用它们,获取它们后您必须将它们转换为 Entity 并保存它们。

创造UserMedDto

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserMedDto {

    private UserMedIdDto userMedIdDto;

    //Setters and Getters
}
Run Code Online (Sandbox Code Playgroud)

创造UserMedIdDto

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
    public class UserMedIdDto {

    @NonNull
    public int drug_id;

    @NonNull
    public String username;

    //Setters and Getters
}
Run Code Online (Sandbox Code Playgroud)

addNewUser在控制器中使用Dtos

@PostMapping("/addNewUserMed")
    public String addNewUser(@RequestBody UserMedDto userMedDto) {
        //Convert UserMedDto to UserMedEntity then send it to addNewUserMed
        userMedService.addNewUserMed(userMedEntity);
        return "success";
    }
Run Code Online (Sandbox Code Playgroud)

这些链接可能有用

1-在 Spring Boot API 上自动将 DTO 映射到实体

2- DTO 到实体以及实体到 DTO 转换