【问题标题】:Can't save data to a database with DTO无法使用 DTO 将数据保存到数据库
【发布时间】:2025-12-27 10:20:09
【问题描述】:

此问题与此处的上一个问题相关: getting null while posting data

我尝试了一个建议的答案,导入了 lombok 并创建了一个 DTO 类,如下所示:

package com.example.dto;
import java.util.HashSet;
import java.util.Set;

import lombok.Data;

@Data
public class TownDTO {
    public String name;
       public String regionid;
}

表城镇与 db 中的区域表相关。当我尝试保存数据时,出现以下异常:

not-null property references a null or transient value : com.example.model.Towns.regionid

这是我的模型类

package com.example.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;

import com.fasterxml.jackson.annotation.JsonIgnore;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "towns")

public class Towns {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    @Column(name = "name")
    private String name;
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
        @JoinColumn(name = "regionid", nullable = false)
        @OnDelete(action = OnDeleteAction.CASCADE)
        private Regions regionid;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Regions getRegionid() {
        return regionid;
    }
    public void setRegionid(Regions regionid) {
        this.regionid = regionid;
    }
    
    
    
}

和存储库如下。 城镇库

package com.example.repository;
import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;

import com.example.model.Towns;
import com.example.model.Regions;
public interface TownsRepository extends JpaRepository<Towns, Integer> {

     List<Towns> findByNameContaining(String name);
     Page<Regions> findByregionid(Integer regionid, Pageable pageable);
        Optional<Regions> findByregionidAndId(Integer regionId, Integer id);

}

区域存储库

package com.example.repository;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import com.example.model.Regions;

public interface RegionsRepository extends JpaRepository<Regions, Integer> {

      List<Regions> findByNameContaining(String name);

}

最后是控制器方法:

@PostMapping("/add")
    public ResponseEntity<TownDTO> createPost(@RequestBody TownDTO townDto) {

        
        // convert DTO to entity
        Towns townRequest = modelMapper.map(townDto, Towns.class);
            //System.out.println(townDto.regionid);
        //System.out.println(townRequest.getName());
        Towns town = townsrepository.save(townRequest);
        

        // convert entity to DTO
        TownDTO townResponse = modelMapper.map(town, TownDTO.class);

        return new ResponseEntity<TownDTO>(townResponse, HttpStatus.CREATED);
    }

我能够打印出 townDTO.regionid 并且值是正确的 2 在我的情况下。但是请求仍然为空。这是邮递员的要求

{
"name": "test",
"regionid": "2"

}

我现在错过了什么?

删除了@jsonignore 并向 DTO 添加了 getter 和 setter

package com.example.dto;
import java.util.HashSet;
import java.util.Set;

import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data

public class TownDTO {
    public String name;
       public String regionid;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getRegionid() {
        return regionid;
    }
    public void setRegionid(String regionid) {
        this.regionid = regionid;
    }
    
       
}

没有任何变化。错误是一样的

【问题讨论】:

  • 听起来像是ModelMapper 的问题,String regionid 是如何映射到Region regionid 的??? (我假设:一点也不/非常平坦)这个区域(2)是否已经存在?调用与连接列相同的引用实体也有点“非常规”/可能会引起混淆。
  • 持久化是什么意思?如果您的意思是保存在区域表中,那么可以。有一条 id=2 的记录
  • 重复 xerx593 所说的内容 - regionid : "2" 是一个字符串值,但您的 Town.regionid 需要一个“Regions”实例。为 townRequest.regionid 返回的 ModelMapper 是什么?错误表明它为空,这意味着您必须自己处理此字符串到区域的转换(您将其标记为 JsonIgnore),并且可能应该使用存储库查找从数据库中获取值为 2 的实例并使用该实例在创建的 townRequest.regionsid 参考中。
  • @Chris 好吧,谢谢。我刚刚从 regionid 中删除了一个 JsonIgnore 并得到了同样的错误。加上 regionid 仍然为空。那怎么转换呢?
  • 我不确定映射器是如何设置的,但我怀疑它是否可以自动理解并知道你想用 String 'int' 值做什么。这不是 Region 实例。它是否反向工作 - regionId 字符串是否在您期望的时候填充?您最好在您的实体中为此 regionId 外键创建一个基本映射,并在您的 DTO 中使用它。只需将关系(或您喜欢的基本关系)标记为可更新 = 假、可插入 = 假,这样 db 列就只有一个可写映射。

标签: java json spring-boot jpa postman


【解决方案1】:

您的 TownDTO 包含字符串 regionid,而您的模型类是区域对象。所以 moddlemapper 无法映射。

//DTO
public String regionid;

//Model
private Regions regionid;

【讨论】: