Java – establish a two to many relationship in JPA / hibernate
I have the following physical relationship issues The game must have two (only two) team objects "Team" can have many "games"
As far as I can see, this is a two - to - many relationship However, I don't know how to model in JPA For example, I want to do such a thing
@Entity public class Team extends BaSEObject { private Long id; private Set<Game> games; @Id @GeneratedValue(strategy = GenerationType.AUTO) public Long getId() {return id;} public void setId(Long id) {this.id = id;} @OneToMany(mappedBy = "game") public Set<Game> getGames() {return games;} public void setGames(Set<Game> games) {this.games = games;} } @Entity public class Game extends BaSEObject { private Long id; private Team team1; private Team team2; @Id @GeneratedValue(strategy = GenerationType.AUTO) public Long getId() {return id;} public void setId(Long id) {this.id = id;} @ HERE IS THE PROBLEM - WHAT ANNOTATION DO I USE? public Team getTeam1() {return team1;} public void setTeam1(Team team1) {this.team1 = team1;} @ HERE IS THE PROBLEM - WHAT ANNOTATION DO I USE? public Team getTeam2() {return team2;} public void setTeam2(Team team1) {this.team2 = team2;} }
However, as you can see, I don't know how to join tables together in terms of annotations Has anyone ever done such a thing? Any ideas, help?
Thank you.
Solution
I want someone to come up with a great solution, but it's a tricky situation. I've never found a way to map well Your choices include:
>Change the way you build relationships For example, you can do this:
@Entity public class GameMembership { Team team; Game game; int gamePosition; // If tracking Team 1 vs Team 2 matters to you }
Then the game has a set < gamemembership >, that is, you model it as many to many The game can still have convenient methods to set team 1 and team 2 (business logic forces only two teams, but they have been completed), but they are mapped back to the collection used by hibernate Abandoning a relationship is two-way – choosing a direction (game → team seems most appropriate) only moves the relationship Find a game that the team participates in and then becomes an operation such as your Dao, rather than an operation that the team itself can access:
public class GameDAO { .... public Collection<Game> gamesForTeam(Team t) { .... Query q = session.createQuery("FROM Game WHERE team1 = :team OR team2 = :team"); q.setParameter("team",t); return q.list(); } }
Or something like that... > continue along your route, but "cheat" at the end of the team The attributes of the game end should be mapped to the normal many to one relationship; Then use mappedby on the team side to represent the control relationship of the game
public class Team { ... @OneToMany(mappedBy="team1") private Set<Game> team1Games; @OneToMany(mappedBy="team2") private Set<Game> team2Games;
Then provide convenient properties for your API (team1games and team2games are for hibernate only):
@Transient public Set<Game> getGames() { Set<Game> allGames = new HashSet<Game>(team1Games); allGames.addAll(team2Games); // Or use google-collections Sets.union() for bonus points return allGames; }
So your class caller, it is transparent and has two attributes