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);
}
}
(E1Repository
とE2Repository
はJpaRepository
を拡張@Repository
注釈付きのインターフェースであるように定義されるように定義されたエンティティとして定義されたエンティティE1
を有します空の体がある)。
私は私のデバッガでc
方法をステップするとき、私は最後の2行em.refresh
後、e1
と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<>();
}
として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になります。私は、このスニペットの前に、result
はmatch
がrobot
が永続状態にあり、永続化状態にある、Hibernateのエンティティのライフサイクルの過渡状態ではないようであるべきであり、result
のmatch
とrobot
プロパティはmatch
とrobot
に設定されていますそれぞれ、
は、スタックオーバーフローや他のサイト上の他の質問に基づいて、私も助けにはならなかった
@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);
}
あなたは 'resultRepository.save(結果)を呼び出す前に、あなたのコードを投稿してくださいでした。あなたはそれを永続化開始時に、あなたのオブジェクトのネットがどのように見えるのアイデアを得るために、'?方法全体を改善するか?このメソッドか、 '@ Transactional'でアノテートされたクラスを含んでいますか? 'match'オブジェクトがnullの場合の作成と保存' Robot'オブジェクトをし、404を与えることの例外を除いて、それは 'Robot'とは取引を持っていない、ので、私は法の前の部分を残していたアンスガー・シュルテ@ –
または「一致」。私は先に進んでそれを追加します。私は、デバッガでCメソッドをステップ実行するとき –
*、私は最後の2つのem.refresh行の後、E1とE2の両方が彼らのセットがクリアされていることがわかり*:まあ、彼らはもちろん、あなたがフラッシュせずにそれらをリフレッシュしので、あなたが今行った変更。なぜあなたはリフレッシュしますか?そして、なぜあなたは管理されたエンティティを再保存しますか?これらの再保存とリフレッシュは役に立たず、逆効果もありません。 )http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#refresh(java.lang.Objectを読む。*リフレッシュ...もしあれば、エンティティに加えられた変更を上書きします* 。 –