2017-03-10 11 views
0

Iはspring + hibernate多対多の関係が永続化されないのはなぜですか?

@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); 
    } 

} 

E1RepositoryE2RepositoryJpaRepositoryを拡張@Repository注釈付きのインターフェースであるように定義されるように定義されたエンティティとして定義されたエンティティE1を有します空の体がある)。

私は私のデバッガでc方法をステップするとき、私は最後の2行em.refresh後、e1e2の両方が彼らのセットがクリアされていることを参照してください。私は、スタックオーバーフローで見つかった他の質問に基づいて

は、私が

@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<>(); 
} 

としてE2を定義しようとしたが、これは助けにはなりませんでした。

(I上記の簡略ケースをテストしようとした前の)元の質問は Iは次のように定義されたクラスRobot有する:

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

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

@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<>(); 
と同様クラス Match

およびクラスResultは、

のように定義されています。

@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; 
} 
と、次のような関係を保存しよう:

*RepositoryはJpaRepositoryを実装スプリングによって作成されたBeanです
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); 

。 このコードが実行されると、resultオブジェクトのhibernateによってinsertステートメントが実行されます(hibernateはすべてのsqlコマンドをコンソールに出力します)が、 "match_robot"テーブルはnoneになります。私は、このスニペットの前に、resultmatchrobotが永続状態にあり、永続化状態にある、Hibernateのエンティティのライフサイクルの過渡状態ではないようであるべきであり、resultmatchrobotプロパティはmatchrobotに設定されていますそれぞれ、

は、スタックオーバーフローや他のサイト上の他の質問に基づいて、私も助けにはならなかった

@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); 
} 
+0

あなたは 'resultRepository.save(結果)を呼び出す前に、あなたのコードを投稿してくださいでした。あなたはそれを永続化開始時に、あなたのオブジェクトのネットがどのように見えるのアイデアを得るために、'?方法全体を改善するか?このメソッドか、 '@ Transactional'でアノテートされたクラスを含んでいますか? 'match'オブジェクトがnullの場合の作成と保存' Robot'オブジェクトをし、404を与えることの例外を除いて、それは 'Robot'とは取引を持っていない、ので、私は法の前の部分を残していたアンスガー・シュルテ@ –

+0

または「一致」。私は先に進んでそれを追加します。私は、デバッガでCメソッドをステップ実行するとき –

+0

*、私は最後の2つのem.refresh行の後、E1とE2の両方が彼らのセットがクリアされていることがわかり*:まあ、彼らはもちろん、あなたがフラッシュせずにそれらをリフレッシュしので、あなたが今行った変更。なぜあなたはリフレッシュしますか?そして、なぜあなたは管理されたエンティティを再保存しますか?これらの再保存とリフレッシュは役に立たず、逆効果もありません。 )http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#refresh(java.lang.Objectを読む。*リフレッシュ...もしあれば、エンティティに加えられた変更を上書きします* 。 –

答えて

0

JpaRepository.save()は、データベースへの変更をフラッシュしません。変更をJpaRepository.flush()またはJpaRepository.saveAndFlush()でフラッシュする必要があります。

関連する問題