如何在@ManyToOne 单向映射中使用spring boot 保存包含子对象的父对象?
Posted
技术标签:
【中文标题】如何在@ManyToOne 单向映射中使用spring boot 保存包含子对象的父对象?【英文标题】:how to save parent object containing child object using spring boot in @ManyToOne unidirectional mapping? 【发布时间】:2020-06-02 04:14:23 【问题描述】:我是春季靴子的新手。我有两个模型类 Party(parent) 和 PartyCategory(child)。 PartyCategory 成功存储数据 id、labelAr 和 labelEn。
现在我在 json 请求中传递子 ID,并在 json 响应中获取 labelAr 和 labelEn 的空值,如下所示。有人可以在这里帮忙做什么和做错什么。
我也粘贴了我的代码。
Json 请求:
"name": "Party A",
"description": "Description of Party A",
"category":
"id": 1
Json 响应;
"id": 6,
"name": "Party A",
"description": "Description of Party A",
"category":
"id": 1,
"labelAr": null,
"labelEn": null
派对.java:
public class Party
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String description;
@ManyToOne(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
@JoinColumn(name = "category_id")
private PartyCategory category;
....setters and getters
PartyCategory.java:-
public class PartyCategory
@Id
@GeneratedValue
private Integer id;
private String labelAr;
private String labelEn;
...setters and getters..
存储库:
public interface PartyCategoryRepository extends JpaRepository<PartyCategory, Integer>
public interface PartyRepository extends JpaRepository<Party, Integer>
服务:
public class PartyServiceImpl
@Autowired
PartyRepository partyRepository;
public Party saveParty(Party party)
return partyRepository.save(party);
控制器:
@RestController
public class PartyController
@Autowired
PartyServiceImpl partyServiceIml;
@PostMapping(value = "/party/save")
public Party saveParty(@RequestBody Party party )
Party returnedParty = partyServiceIml.saveParty(party);
return returnedParty;
【问题讨论】:
【参考方案1】:问题是您发布的类别未被识别为现有类别。
然后您可以执行以下操作。首先,创建一个 Jackson 转换器类来自定义 Json 反序列化。我不确定这些是否是 Spring 管理的,但它们是这样的,因此您可以注入必要的存储库。
import com.fasterxml.jackson.databind.util.StdConverter;
@Component
public class CategoryConverter extends StdConverter<Integer, PartyCategory>
@Autowired
private PartyCategoryRepository repo;
@Override
public PartyCategory convert(Integer value)
return repo.findById(value).get();
然后按如下方式更新您的实体,以便通过上面创建的转换器处理 category
Json 属性。请注意,实际上我会使用 Jackson 混合来应用此自定义反序列化器,因为这将避免使用 Json 处理指令“污染”实体类。您可以查看如何执行此操作。
@Entity
public class Party
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String description;
@ManyToOne
@JoinColumn(name = "category_id")
@JsonDeserialize(converter = CategoryConverter.class) //in real life use a 'mix-in'
private PartyCategory category;
然后你可以像下面这样发布 JSON,我们只需指定现有类别的 id:
"name": "Party A",
"description": "Description of Party A",
"category": 1
通过增强此解决方案以按照建议使用混入,然后可以将视图模型与实体模型清晰地分开,而无需创建通常会在很大程度上复制实体模型并且需要繁琐的映射的 DTO 层处理转换的代码。
【讨论】:
【参考方案2】:首先,对数据库和其他服务使用相同的实体并不是一个好习惯。它们应该是单独的实体,通常其余服务的实体称为 DTO(数据访问对象)。
现在,关于您的问题,您的代码中发生的情况是正常的,因为您在保存新 Party 时用空值覆盖了与 ID 1 关联的 PartyCategory labelAr 和 labelEn,因为您没有为这两个标签。
return partyRepository.save(party);
如果你想避免这个问题,你必须首先从数据库中检索 PartyCategory 数据,设置为 Party 实体,然后将其保存到数据库中。像这样的:
public class PartyServiceImpl
@Autowired
PartyRepository partyRepository;
@Autowired
PartyCategoryRepository partyCategoryRepository;
public Party saveParty(Party party)
PartyCategory partyCategory = partyCategoryRepository.findById(party.getPartyCategory().getId());
party.setPartyCategory(partyCategory);
return partyRepository.save(party);
【讨论】:
以上是关于如何在@ManyToOne 单向映射中使用spring boot 保存包含子对象的父对象?的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate - 自定义查询未通过 ManyToOne 单向关系的 child 参数找到实体
为啥在这个 Hibernate 映射中使用 @ManyToOne 而不是 @OneToOne?
为啥 Eclipselink 不在单向 @ManyToOne 关系中生成 ON DELETE CASCADE 子句?
如何正确映射@OneToMany 和@ManyToOne 关系,以便我可以保存和更新@OneToMany 端(有或没有@ManyToOne 端)