当前位置: 首页 > 知识库问答 >
问题:

Spring冬眠 为什么多对多关系没有持续存在?

谷梁英毅
2023-03-14

我有一个实体 E1 定义为

@Entity
public class E1 {
    @Id
    @GeneratedValue
    public long id;
    @ManyToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(
            name="e1_e2",
            joinColumns = @JoinColumn(name = "e2_id"),
            inverseJoinColumns = @JoinColumn(name = "e1_id")
    )
    public Set<E2> e2s = new HashSet<>();
}

实体 E2 定义为

@Entity
public class E2 {
    @Id
    @GeneratedValue
    public long id;
    @ManyToMany(mappedBy = "e2s")
    public Set<E1> e1s = new HashSet<>();
}

控制器定义为:

@RestController
@RequestMapping("/")
public class C1 {
    private final E1Repository e1Repository;
    private final E2Repository e2Repository;

    @PersistenceContext
    EntityManager em;

    @Autowired
    public C1(E1Repository e1Repository, E2Repository e2Repository) {
        this.e1Repository = e1Repository;
        this.e2Repository = e2Repository;
    }

    @Transactional
    @RequestMapping(method = POST)
    public void c(){
        E1 e1 = new E1();
        E2 e2 = new E2();

        e1Repository.save(e1);
        e2Repository.save(e2);

        em.refresh(e1);
        em.refresh(e2);

        e1.e2s.add(e2);
        e2.e1s.add(e1);

        e1Repository.save(e1);
        e2Repository.save(e2);

        em.refresh(e1);
        em.refresh(e2);
    }

}

E1RepositoryE2Repository,是@repositoyannotated接口,扩展JpaRepository并具有空体)。

当我在调试器中单步执行c方法时,我看到在最后两行em.refresh行之后,e1e2都清除了它们的集合。

基于我在Stack Overflow上发现的其他问题,我尝试将E2定义为

@Entity
public class E2 {
    @Id
    @GeneratedValue
    public long id;
    @ManyToMany(cascade = CascadeType.PERSIST)
    @JoinTable(
            name="e1_e2",
            inverseJoinColumns = @JoinColumn(name = "e2_id"),
            joinColumns = @JoinColumn(name = "e1_id")
    )
    public Set<E1> e1s = new HashSet<>();
}

但这于事无补。

原问题(在我尝试测试上面的简化案例之前)我有一个类< code>Robot,定义如下:

@Entity
class Robot{
    @Id
    @GeneratedValue
    private long id;

    @ManyToMany(mappedBy="robots")
    private Set<Match> matches = new HashSet<>();
}

和一个类< code>Match类似于

@Entity
class Robot{
    @Id
    @GeneratedValue
    private long id;
    @ManyToMany(cascade={CascadeType.Persist,CascadeType.Merge})
    @JoinTable(
        name = "match_robot",
        joinColumns = {@JoinColumn(name = "Match_id")},
        inverseJoinColumns = {@JoinColumn(name = "Robot_id")}
)
private Set<Robot> robots = new HashSet<>();

类<code>结果<code>的定义类似于

@Entity
public class Result {
    @Id
    @GeneratedValue
    private long id;

    @ManyToOne(optional = false)
    private Match match;

    @ManyToOne(optional = false)
    @NotNull(groups = {Default.class, Creating.class})
    private Robot robot;
}

并尝试保存关系,如下所示:

resultRepository.save(result);
match.getRobots().add(result.getRobot());
result.getRobot().getMatches().add(match);
robotRepository.save(result.getRobot());
matchRepository.save(match);
entityManager.refresh(result);
entityManager.refresh(result.getRobot());
entityManager.refresh(match);

其中< code>*Repository是spring创建的实现JpaRepository的beans。运行这段代码时,hibernate会为< code>result对象运行一个insert语句(hibernate会将其所有sql命令输出到控制台),但不会为“match_robot”表运行任何语句。在这段代码之前,< code>result处于hibernate实体生命周期的瞬态,< code>match处于持久状态,< code>robot处于持久状态,< code>result的< code>match和< code>robot属性已分别设置为< code>match和< code>robot。

基于栈溢出和其他站点的其他问题,我还尝试将matches变量定义为

@ManyToMany(cascade = CascadeType.PERSIST)
@JoinTable(
        name = "match_robot",
        inverseJoinColumns = {@JoinColumn(name = "Match_id")},
        joinColumns = {@JoinColumn(name = "Robot_id")}
)
private Set<Match> matches = new HashSet<>();

除此之外,我看到的唯一建议是在坚持之前确保多对多关系中的两个实体彼此一致,但是,据我所知,我正在这样做。

我该如何坚持这段感情?

编辑:上下文的完整方法:

@Transactional
@RequestMapping(value = "/{match:[0-9]+}/results", method = RequestMethod.POST)
public ResultResource createResult(@PathVariable Match match,
                                   @Validated(Result.Creating.class)
                                   @RequestBody Result result) {
    if (match == null) throw new ResourceNotFoundException();

    result.setScorecard(scorecardRepository
            .findById(result.getScorecard().getId()));
    if (result.getScorecard() == null) {
        throw new ScorecardDoesNotExistException();
    }

    result.setMatch(match);

    //remove null scores
    result.getScores().removeIf(
            fieldResult -> fieldResult.getScore() == null
    );

    //replace transient robot with entity from database
    Robot existingRobot = robotRepository
            .findByNumberAndGame(result.getRobot().getNumber(),result.getRobot().getGame());
     if (existingRobot == null) { //create new robot
        //find team for this robot
        Team existingTeam = teamRepository
                .findByNumberAndGameType(
                        result.getRobot().getNumber(),
                        result.getScorecard().getGame().getType());
        if (existingTeam == null) {
            Team team = new Team();
            team.setNumber(result.getRobot().getNumber());
            team.setGameType(result.getMatch().getEvent().getGame().getType());
            team.setDistrict(result.getMatch().getEvent().getDistrict());
            teamRepository.save(team);
            result.getRobot().setTeam(team);
        }
    else result.getRobot().setTeam(existingTeam);
             result.getRobot().setGame(result.getMatch().getEvent().getGame());

        robotRepository.save(result.getRobot());
        entityManager.refresh(result.getRobot());
    } else result.setRobot(existingRobot);
    List<Robot> all = robotRepository.findAll();

    //replace transient FieldSections with entities from database
    //todo: reduce database hits
    //noinspection ResultOfMethodCallIgnored
    result.getScores().stream()
          .peek(fieldResult -> fieldResult.setField(
                  fieldSectionRepository.findByIdAndScorecard(
                          fieldResult.getField().getId(),
                          result.getScorecard())))
              .peek(fieldResult -> {
              if (fieldResult.getField() == null)
                  throw new ScoresDoNotExistException();
          })
          .forEach(fieldResult->fieldResult.setResult(result));


    if (!result.scoresMatchScorecardSections()) {
        throw new ScoresDoNotMatchScorecardException();
    }

    if (!result.allMissingScoresAreOptional()) {
        throw new RequiredScoresAbsentException();
    }

    if (!result.gameMatchesScorecard()) {
        throw new GameDoesNotMatchScorecardException();
    }

    resultRepository.save(result);
    match.getRobots().add(result.getRobot());
    result.getRobot().getMatches().add(match);
    robotRepository.save(result.getRobot());
    matchRepository.save(match);
    entityManager.refresh(result);
    entityManager.refresh(result.getRobot());
    entityManager.refresh(match);
    return new ResultResourceAssembler().toResource(result);
}

共有1个答案

缪嘉志
2023-03-14

JpaRepository.save() 不会将更改刷新到数据库。有必要使用 JpaRepository.flush()JpaRepository.saveAndFlush() 冲洗更改。

 类似资料:
  • 问题内容: 我有实体类A和C。它们正在映射表tblA和tblC,并且它们之间具有多对多关系,而tblB则在它们之间进行映射。tblB包含A_ID,C_ID和SetDate,最后一个是它的设置日期,因此是关系的属性。我的问题是,如何最好地映射此属性?目前,它们尚未映射,如下所示: A: C: 我应该如何从中获取tblB.SetDate? 干杯 尼克 问题答案: 据我所知, 不可能 以这种方式进行映射

  • 问题内容: 我在个人课程和汽车课程之间有一对多的关系。一个人可以拥有许多汽车,反之亦然。我正在使用Restful API发布数据。我的注释和Get服务运行正常,但是我的后服务在每次尝试插入新数据时都抛出“ 。子表插入为” 。 这是我的代码的一部分。 人.java 汽车.java 我的服务等级: 问题答案: 此注释: 有两个后果: 暗示这是关系的拥有方。这意味着,每当要在和之间建立关系时, 都需要通

  • 问题内容: 我的Java bean与我有很多关系。当我使用如下方式定义变量时: 我得到那个错误: 当我使用时,一切似乎都运行良好。 我想问的是,在使用多对多关系时,哪一个关系用于逻辑概念或(因为列表可能有重复项和集合,但是性能和其他问题又如何)? 问题答案: 从关系数据库的角度来看,这是一个集合。数据库不会保留顺序,并且使用a 是没有意义的,它们的顺序是不确定的(除非使用所谓的 索引集合 )。 使

  • 问题内容: 问题 首先,我想知道我的数据库结构很糟糕,但是目前我无法更改它。 话虽这么说,我需要在Hibernate(4.2.1)中创建一对多的双向关系,该关系不涉及主键(关系的“父”侧仅包含唯一键)并且不涉及联接表。表示这种关系的外键是从“子”到“父”的反向指针(请参见下文)。我已经搜索并尝试了各种不同的注释配置,但是没有运气。我要的是可能的吗? 数据库 GLOBAL_PART PART_REL

  • 我正在学习JPA,我有两个实体(Customer和CheckingAccount),其中第一个实体与第二个实体有一对多关系。CheckingAccount是BankAccount类的子类。我正在使用MySQL。 我在测试程序中创建了两个支票账户,并将它们分配给我创建的一个客户。 在我持久化所有内容并检查数据库后,我希望在CheckingAccount表中看到我所做的2行,在Customer表中看到

  • 我在Spring Boot应用程序中有多对多关系。我需要创建“收藏夹”功能与用户和广告。用户可以喜欢许多广告,也可以由许多用户喜欢的广告。这就是它们之间的关系: 用户类: 这是广告类: 这是控制器类: 这是UserServiceImplementation: 要插入收藏夹,用户需要点击广告,该功能运行良好。此外,我可以发送用户收藏的所有广告列表。但是当我想从用户收藏夹中删除一些添加时(用户想从他的