java - Spring Data JPA - 使用现有的嵌套子对象保留新对象

标签 java spring hibernate spring-boot spring-data-jpa

我确实有两个名为 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;

}

我的 SchoolController(Rest Controller )有一个 create 方法,该方法采用 SchoolDTO(目前它具有与实体相同的结构)。

当我发布 DTO 时,嵌套子列表级别仅使用现有级别 ID 填充(因为之前创建了级别)。

当我尝试通过 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:

通过迭代每个级别 Id 可以解决问题...使用 JPA 存储库方法 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());
    }

我的问题是:这是在 Spring Data 中发布关联的“唯一”正确方法吗?或者有什么更好的办法吗?

最佳答案

addLevelToPackage函数中为什么要使用mapschoolService.findById(id).map..如果我认为schoolService会返回只有一个具有给定 ID 的实体 School 实例。 我认为用以下内容替换 map 就足够了:

...
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));
...

关于java - Spring Data JPA - 使用现有的嵌套子对象保留新对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60458490/

相关文章:

java - 在 Ldap 搜索上设置方法超时

使用连接表 hibernate 一对多,并 hibernate 注释

java - 如何在 java 中获取带注释的值?

java - 使用带有 minimizeJar = true 的阴影时出现 NullPointerException

java - Spring + hibernate : Expected type: java. util.SortedSet,实际值: org. hibernate.collection.internal.PersistentSet

java - 如何将 JButtons 从列表连接到 actionListener

hibernate 事务 ID

java - 与 spring 的 Servlet 映射

java - 从 MongoDB 生成模型实体类

java - 跨应用程序的多个实例维护 StringBuffer 类中的日志