从其他实体检索ID时的Spring Boot JPA反序列化问题

Posted

技术标签:

【中文标题】从其他实体检索ID时的Spring Boot JPA反序列化问题【英文标题】:Spring boot JPA deserialization problem when retrieving ID from other entity 【发布时间】:2020-10-17 06:02:30 【问题描述】:

我正在创建一个 Web 程序,以使用 spring boot、tomcat 和 JPA 映射存储占用级别。 我已经创建了成员模型/服务/控制器,当我尝试对其进行更新、创建、删除或从中获取信息时,它可以正常工作。

但也没有创建商店,当我使用 ownerId 创建商店时,我收到一条错误消息:

错误信息

[org.springframework.http.converter.HttpMessageNotReadableException:JSON 解析错误:无法构造com.project.so2.models.Member 的实例(尽管至少存在一个创建者):没有字符串参数构造函数/工厂方法可以从字符串值反序列化('1');嵌套异常是 com.fasterxml.jackson.databind.exc.MismatchedInputException:无法构造 com.project.so2.models.Member 的实例(尽管至少存在一个 Creator):没有从字符串值反序列化的字符串参数构造函数/工厂方法('1') 在 [来源:(PushbackInputStream); line: 4, column: 18] (通过引用链: com.project.so2.models.Store["owner_id"])]

我已经尝试查找类似的问题,但我没有看到任何适用的解决方案。

模型

商店

@Entity(name = "Store")
@Table(name = "store")
@SequenceGenerator(name = "store_id")
public class Store 

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "store_id")
    @Column(name = "id")
    private long id;

    //many stores to one owner
    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @OnDelete(action = OnDeleteAction.CASCADE)
    @JoinColumn(name = "owner_id", referencedColumnName = "id")
    private Member owner_id;
    
    //one store to many occupation level
    @OneToMany(mappedBy = "store")
    private List<Occupation> store_occupation;
    
    @OneToOne(mappedBy = "store")
    private Location location;

    @Column(name = "name")
    private String name;

    @Column(name = "square_footage")
    private String square_footage;

    public Store() 
    

会员

@Entity(name = "Member")
@Table(name = "member")
@SequenceGenerator(name = "member_id")
public class Member 
    
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_id")
    @Column(name = "id")
    private long id;
    
    @Enumerated(EnumType.STRING)
    @Column(name = "role")    
    private Role role;//customer|admin|store_owner
    
    @Column(name = "mail", unique = true)
    private String mail;
    
    @Column(name = "name")
    private String name;

    @OneToMany(mappedBy = "owner_id")
    private List<Store> stores;
    
    
    
    /**
     * REALM to store passwords
     */
    
    @CreationTimestamp
    @Temporal(javax.persistence.TemporalType.DATE)
    private Date createdAt;
    
    @UpdateTimestamp
    private Date updateAt;

存储控制器

@RestController
@RequestMapping("/store")
@ControllerAdvice()
@CrossOrigin
public class StoreController 
    @Autowired
    private StoreService storeservice;

    @PostMapping("/create")
    public ResponseEntity<HttpStatus> createStore(@RequestBody Store store) 
        try 
            this.storeservice.saveStore(store);
            return new ResponseEntity<>(HttpStatus.CREATED);
         catch (Exception e) 
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        
    

商店服务

@Service
public class StoreService 
    
    @Autowired
    private StoreRepository storeRepository;//

    public void saveStore(Store store) 
        this.storeRepository.save(store); 
    

请求负载:


    "name": "Pingo Azedo",
    "square_footage": "25m^2",
    "owner_id":
        "member_id": "1"
    

老实说,我不明白这个问题,也不知道如何解决它。如果有人可以提供帮助,将不胜感激!

【问题讨论】:

可以发一下全班商店和会员吗? 我刚刚做了,只是省略了 getter 和 setter @Hưng Chu 你能贴出异常的堆栈跟踪吗? 刚刚这样做了@YohanAloka 这可能是请求负载的问题,您也可以发布请求负载吗? 【参考方案1】:

您正试图从 json 中反序列化成员,但杰克逊不知道如何仅使用“member_id”填写此成员,并且错误很明显是“找不到带有 String 的构造函数”。因此,为了获取成员 ID,您需要添加新的类请求 dto,例如:

String name;
String footage;
Long owner_id;

在您的控制器中使用您的新类,现在使用 owner_id,使用存储库在您的数据库中找到它,然后将其设置到您的商店。

【讨论】:

【参考方案2】:

您需要在有效负载中使用属性名称,而不是列名称。如下更改您的请求负载,


  "name": "Pingo Azedo",
  "square_footage": "25m^2",
  "owner_id":
       "id" : 1
    

【讨论】:

以上是关于从其他实体检索ID时的Spring Boot JPA反序列化问题的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Spring Boot 项目中的子子表中检索数据?

Spring Boot 和事务边界

JPA Spring Boot 微服务 - 使用两个多对一映射持久化实体时的无限循环

检索表连接的结果

Spring Boot:如何从 JPA/Hibernate 注释中保持 DDD 实体的清洁?

Spring JPA,Hibernate 仅从其他实体获取 PK 或 Id