简体   繁体   English

Spring Data JPA - 使用现有嵌套子项持久化新对象

[英]Spring Data JPA - Persisting new Object with existing nested child

I do have two entities called School and Level with a Many-To-Many relationship.我确实有两个名为 School 和 Level 的实体,它们具有多对多关系。

@Data
@Entity
public class School {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "school_generator")
    @SequenceGenerator(name="school_generator", sequenceName = "school_seq", allocationSize=1)
    @Column(name = "school_id")
    private Long id;

    @NotBlank
    private String name;

    @NotBlank
    private String city;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(
            name = "school_level",
            joinColumns = @JoinColumn(name = "school_id"),
            inverseJoinColumns = @JoinColumn(name = "level_id"))
    private Set<Level> levels = new HashSet<>();

}

@Data
@Entity
public class Level implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "level_generator")
    @SequenceGenerator(name = "level_generator", sequenceName = "level_seq", allocationSize = 1)
    @Column(name = "level_id")
    private Long id;

    @NotBlank
    @Column(nullable = false, unique = true)
    private String name;

}

My SchoolController , Rest controller, has a create method which takes a SchoolDTO (for now it has the same structure as the entity).我的SchoolController ,Rest 控制器,有一个采用 SchoolDTO 的 create 方法(现在它与实体具有相同的结构)。

When I post the DTO, the nested child list Levels are populated only with existing Levels ids (since Levels are created previously).当我发布 DTO 时,嵌套的子列表 Levels 仅填充了现有的 Levels id(因为之前创建了 Levels)。

When I try to save through the JPARepository save method...An exception with this message is thrown:当我尝试通过 JPARepository 保存方法保存时...抛出此消息的异常:

"detached entity passed to persist: com.salimrahmani.adawat.domain.Level; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.salimrahmani.adawat.domain.Level",
    "trace": "org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist:

The problem is solved by iterating through each Level Id ...get the references by using the JPA Repository method getOne (which calls entityManager.getReference ) and then loads the right model and then persist successfully.问题是通过迭代每个 Level Id 来解决的……使用 JPA Repository 方法getOne (调用entityManager.getReference )获取引用,然后加载正确的模型,然后成功持久化。

@PostMapping("/{id}/grades")
public ResponseEntity<SchoolDTO> addLevelToPackage(@PathVariable Long id, @RequestBody @Valid LevelDTO levelDTO) {
        return schoolService.findById(id)
                .map(school -> {
                    Level level = levelMapper.map(levelDTO);

                    if(level.getId() != null) {
                        level = levelService.getOne(level.getId());
                        school.getLevels().add(level);
                    } // else error

                    School saved = schoolService.save(school);

                    return ResponseEntity.ok(schoolMapper.map(saved));

                }).orElseGet(() -> ResponseEntity.notFound().build());
    }

My question is: Is this the "only" correct way to posting association in Spring Data?我的问题是:这是在 Spring Data 中发布关联的“唯一”正确方法吗? Or, is there any better way?或者,有没有更好的办法?

In the addLevelToPackage function Why using the map schoolService.findById(id).map.. if as I think the schoolService will return only one instance of the entity School with the given id.addLevelToPackage函数中为什么使用map schoolService.findById(id).map..如果我认为 schoolService 将仅返回具有给定 id 的实体 School 的一个实例。 I think replacing the map with the following would be enough:我认为用以下内容替换地图就足够了:

...
School theSchool = schoolService.findById(id);
Level theLevel = levelService.getOne(levelDTO.getId());
theSchool.getLevels().add(theLevel);
School saved = schoolService.save(theSchool);
return ResponseEntity.ok(schoolMapper.map(saved));
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM