正确合并集合并不是一件容易的事!推荐Vlad的例子 文章 的Spring Boot示例,只有手工进行集合合并。
关键点:
假设tournament和tennis_player两个表中有数据:
INSERT INTO tournament (id, name) VALUES (1, 'Roland Garros'); INSERT INTO tournament (id, name) VALUES (2, 'US Open'); INSERT INTO tennis_player (id, name, tournament_id) VALUES (1, 'Rafael Nadal', 1); INSERT INTO tennis_player (id, name, tournament_id) VALUES (2, 'Roger Federer', 1); INSERT INTO tennis_player (id, name, tournament_id) VALUES (3, 'David Ferer', 2); INSERT INTO tennis_player (id, name, tournament_id) VALUES (4, 'Andy Murray', 2); INSERT INTO tennis_player (id, name, tournament_id) VALUES (5, 'Del Potro', 2); INSERT INTO tennis_player (id, name, tournament_id) VALUES (6, 'Novak D', 2); INSERT INTO tennis_player (id, name, tournament_id) VALUES (7, 'John Isner', 2);
Tournament实体:和TennisPlayer 是双向一对多关系
@Entity
<b>public</b> <b>class</b> Tournament implements Serializable {
<b>private</b> <b>static</b> <b>final</b> <b>long</b> serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
<b>private</b> Long id;
<b>private</b> String name;
@OneToMany(cascade = CascadeType.ALL,
mappedBy = <font>"tournament"</font><font>, orphanRemoval = <b>true</b>)
<b>private</b> List<TennisPlayer> tennisPlayers = <b>new</b> ArrayList<>();
</font>
TennisPlayer 实体:
@Entity
<b>public</b> <b>class</b> TennisPlayer implements Serializable {
<b>private</b> <b>static</b> <b>final</b> <b>long</b> serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
<b>private</b> Long id;
<b>private</b> String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = <font>"tournament_id"</font><font>)
<b>private</b> Tournament tournament;
</font>
仓储:
@Repository
@Transactional(readOnly = <b>true</b>)
<b>public</b> <b>interface</b> TournamentRepository <b>extends</b> JpaRepository<Tournament, Long> {
@Query(value=<font>"SELECT t FROM Tournament t JOIN FETCH t.tennisPlayers WHERE t.name = ?1"</font><font>)
Tournament tournamentAndPlayers(String name);
}
@Repository
@Transactional(readOnly = <b>true</b>)
<b>public</b> <b>interface</b> TennisPlayerRepository <b>extends</b> JpaRepository<TennisPlayer, Long> {
@Query(value = </font><font>"SELECT p FROM TennisPlayer p JOIN p.tournament t WHERE t.name = ?1"</font><font>)
List<TennisPlayer> playersOfTournament(String name);
}
</font>
在服务中进行两个实体集合的合并:
@Service
<b>public</b> <b>class</b> TennisService {
<b>private</b> <b>final</b> TournamentRepository tournamentRepository;
<b>private</b> <b>final</b> TennisPlayerRepository tennisPlayerRepository;
<b>public</b> TennisService(TournamentRepository tournamentRepository,
TennisPlayerRepository tennisPlayerRepository) {
<b>this</b>.tournamentRepository = tournamentRepository;
<b>this</b>.tennisPlayerRepository = tennisPlayerRepository;
}
<b>public</b> List<TennisPlayer> fetchPlayersOfTournament(String name) {
<b>return</b> tennisPlayerRepository.playersOfTournament(name);
}
@Transactional
<b>public</b> <b>void</b> updatePlayersOfTorunament(String name, List<TennisPlayer> players) {
Tournament tournament = tournamentRepository.tournamentAndPlayers(name);
System.out.println(<font>"-------------------------------------------------"</font><font>);
</font><font><i>// Remove the existing database rows that are no </i></font><font>
</font><font><i>// longer found in the incoming collection (players)</i></font><font>
</font><font><i>//删除传入集合中不再存在的现有数据库行</i></font><font>
tournament.getTennisPlayers().removeIf((t) -> !players.contains(t));
</font><font><i>// Update the existing database rows which can be found </i></font><font>
</font><font><i>// in the incoming collection (players)</i></font><font>
</font><font><i>//更新现有的可以在传入集合中找到的数据库行</i></font><font>
</font>
List<TennisPlayer> newPlayers = players.stream()
.filter((t) -> !tournament.getTennisPlayers().contains(t))
.collect(Collectors.toList());
players.stream()
.filter((t) -> !newPlayers.contains(t))
.forEach((t) -> {
t.setTournament(tournament);
TennisPlayer mergedPlayer = tennisPlayerRepository.save(t);
tournament.getTennisPlayers().set(
tournament.getTennisPlayers().indexOf(mergedPlayer),
mergedPlayer);
});
<font><i>// Add the rows found in the incoming collection, </i></font><font>
</font><font><i>// which cannot be found in the current database snapshot</i></font><font>
newPlayers.forEach((t) -> tournament.addTennisPlayer(t));
}
}
</font>
手工合并集合的调用:
System.out.println(<font>"------------------- Players from US Open --------------------"</font><font>);
List<TennisPlayer> players = tennisService.fetchPlayersOfTournament(</font><font>"US Open"</font><font>);
players.forEach((t) -> System.out.println(</font><font>"Us Open: "</font><font> + t.getName() + </font><font>" | id:("</font><font> + t.getId() + </font><font>")"</font><font>));
System.out.println(</font><font>"---------- Players from US Open Updated Detached ------------"</font><font>);
</font><font><i>// ,update first player name</i></font><font>
players.get(0).setName(</font><font>"Fernando Verdasco"</font><font>);
</font><font><i>// remove second player</i></font><font>
players.remove(1);
</font><font><i>// add a new player</i></font><font>
TennisPlayer player = <b>new</b> TennisPlayer();
player.setName(</font><font>"Alexander Zverev"</font><font>);
players.add(player);
players.forEach((t) -> System.out.println(</font><font>"Us Open: "</font><font> + t.getName() + </font><font>" | id:("</font><font> + t.getId() + </font><font>")"</font><font>));
System.out.println(</font><font>"----------------- Players from US Open Merged ----------------"</font><font>);
tennisService.updatePlayersOfTorunament(</font><font>"Us Open"</font><font>, players);
players.forEach((t) -> System.out.println(</font><font>"Us Open: "</font><font> + t.getName() + </font><font>" | id:("</font><font> + t.getId() + </font><font>")"</font><font>));
</font>
源代码可以在 这里 找到 。