Hibernate中@NamedEntityGraph子图无法识别cities属性问题求解
问题核心原因
- 你在
Country类上定义了2个@NamedEntityGraph注解,但没有按照JPA规范用@NamedEntityGraphs容器注解包裹,导致第二个名为graph.CountryPrefectureDistrictCities的实体图没有被系统解析注册,自然无法识别其中定义的cities属性。 - 当前所有
@OneToMany注解的级联策略仅配置了CascadeType.REFRESH,无法实现保存Country时自动级联保存子层级对象的需求。
修复步骤
1. 修正实体图配置
给Country类添加@NamedEntityGraphs容器注解包裹两个实体图定义:
@Entity @Table(name = "countries") @Getter @Setter @AllArgsConstructor // 新增容器注解包裹多个NamedEntityGraph @NamedEntityGraphs({ @NamedEntityGraph(name = "graph.prefectures", attributeNodes = @NamedAttributeNode(value = "prefectures")), @NamedEntityGraph( name = "graph.CountryPrefectureDistrictCities", attributeNodes = @NamedAttributeNode(value = "prefectures", subgraph = "subgraph.prefectures"), subgraphs = { @NamedSubgraph(name = "subgraph.prefectures", attributeNodes = @NamedAttributeNode(value = "district", subgraph = "subgraph.district")), @NamedSubgraph(name = "subgraph.district", attributeNodes = @NamedAttributeNode(value = "cities")) }) }) public class Country implements Serializable { // 原有代码保持不变 }
2. 调整级联策略
给所有层级的@OneToMany注解添加CascadeType.PERSIST和CascadeType.MERGE级联类型,实现自动保存子对象:
- Country类的prefectures属性:
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "country", orphanRemoval = true) private Set<Prefectures> prefectures = new HashSet();
- Prefectures类的district属性:
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "prefectures", orphanRemoval = true) private Set<District> district = new HashSet();
- District类的cities属性:
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH, CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "district", orphanRemoval = true) @JsonProperty("cities") private Set<City> cities = new HashSet();
3. 维护双向关联关系
构建层级对象时必须手动给每个子对象设置父对象引用,否则外键字段会为空导致保存失败,示例代码:
// 构建根对象 Country country = new Country(); country.setCountryName("测试国家"); // 构建省级对象并绑定父关联 Prefectures prefecture = new Prefectures(); prefecture.setPrefectureName("测试省份"); prefecture.setCountry(country); // 构建区级对象并绑定父关联 District district = new District(); district.setDistrictDescription("测试区县"); district.setPrefectures(prefecture); // 构建市级对象并绑定父关联 City city = new City(); city.setCityDescription("测试城市"); city.setDistrict(district); // 子对象加入父集合 district.getCities().add(city); prefecture.getDistrict().add(district); country.getPrefectures().add(prefecture); // 仅保存根对象即可自动级联保存所有子层级 countryRepository.save(country);
完成以上修改后,实体图可以正常识别cities属性,同时保存Country时会自动持久化所有关联的子层级数据。
内容的提问来源于stack exchange,提问作者Ugleethyn
相关产品推荐
相关产品推荐

