Моделирование отношений два ко многим в JPA / Hibernate - PullRequest
10 голосов
/ 01 февраля 2010

У меня следующая проблема отношения сущностей. «Игра» должна иметь два (и только два) объекта «Команда». «Команда» может иметь много «Игр»

Насколько я понимаю, это отношения между двумя. Однако ... я не знаю, как смоделировать это в JPA. Например, я собирался сделать что-то вроде этого ...

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

Но, как вы видите, я не уверен, как связать таблицы вместе со стороны аннотации. Кто-нибудь когда-нибудь делал что-то подобное раньше? Есть идеи, помогите?

Большое спасибо!

Ответы [ 5 ]

6 голосов
/ 02 февраля 2010

Я бы хотел, чтобы кто-то придумал отличное решение для этого, но это сложная ситуация, которую я так и не смог найти способ очень хорошо отобразить. Ваши варианты включают:

  1. Измените способ моделирования отношений. Например, у вас может быть что-то вроде:

    @Entity
    public class GameMembership {
       Team team;
       Game game;
       int gamePosition; // If tracking Team 1 vs Team 2 matters to you
    }
    

    и затем Game имеет Collection<GameMembership>, т.е. вы моделируете его как «многие ко многим». Game может по-прежнему иметь удобные методы для настройки Команды 1 и Команды 2 и т. Д. (Бизнес-логика для обеспечения наличия только 2 Команд, однако это сделано), но они отображаются на Collection, как используется Hibernate. *

  2. Откажитесь от двунаправленного отношения - выберите одно направление (GameTeam кажется наиболее подходящим) и дремайте только в этом отношении. Обнаружение, что Games, в который вовлечен Team, становится операцией вашего DAO и т. Д., А не чем-то, что доступно из самого Team:

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

    или что-то подобное ...

  3. Продолжайте движение по маршруту, по которому вы идете, но читером на конце Team. Свойства на стороне Game должны отображаться как нормальные отношения многие-к-одному; затем использовал mappedBy в конце Team, чтобы указать, что Game 'контролирует' отношения.

    public class Team {
            ...
            @OneToMany(mappedBy="team1")
            private Set<Game> team1Games;
            @OneToMany(mappedBy="team2")
            private Set<Game> team2Games;
    

    и , тогда имеют удобное свойство для вашего API (team1Games и team2Games только для использования Hibernate):

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

    так что для абонентов вашего класса ясно, что есть 2 свойства.

2 голосов
/ 02 февраля 2010

У вас есть отношения @OneToMany (я полагаю, у игры есть отношения @ManyToOne с Team), мой совет:

Используйте инкапсуляцию, чтобы получить цель

@Entity
public class Team {

    private Game game1;
    private Game game2;

    private List<Game> gameList = new ArrayList<Game>();

    public void setGame1(Game game1) {
        // You can use index 0 to store your game1
        if(getGameList().size == 0)
            getGameList().add(game1);
        else
            getGameList().set(0, game1);
    }

    @Transient
    public Game getGame1() {
        if(getGameList().size() == 0)
            return null;

        return getGameList().get(0);
    }

    public void setGame2(Game game2) {
        // You can use index 1 to store your game2
        switch(getGameList().size()) {
            case 0:
                getGameList().add(null);

                getGameList().add(game2);
            break;
            case 1:
                getGameList().add(game2);
            break;
            case 2:
                getGameList().set(1, game2);
            break;
        }
    }

    @Transient
    public Game getGame2() {
        if(getGameList().size() < 2)
            return null;

        return getGameList().get(1);
    }

    @OneToMany
    @JoinColumn(name="TEAM_ID")
    public List<Game> getGameList() {
        return this.gameList;
    }

}

Знайте, что иногда вы должны выполнять свою работу вручную. Таким образом, инкапсуляция может быть ключом к вашему вопросу.

С уважением,

2 голосов
/ 01 февраля 2010

Подумайте, что произойдет, если в ваших играх будет первый игрок - команда (выбранная из списка команд) и второй игрок - компьютер (выбранный из списка компьютеров):

  • Вашим первым игроком будет внешний ключ в таблице команд.
  • Ваш второй игрок будет внешним ключом в компьютерном столе.

Если вы замените «компьютер» в качестве игрока другой «командой», вы получите два внешних ключа в таблице команд.

Мой JPA немного ржавый, но я считаю, что вы моделируете отношения с внешним ключом с аннотацией @OneToOne, например:

@OneToOne(cascade = {CascadeType.ALL}, optional = false)
@JoinColumn(name = "team1")

и второй с:

@OneToOne(cascade = {CascadeType.ALL}, optional = false)
@JoinColumn(name = "team2")
1 голос
/ 01 февраля 2010

Я думаю, у вас есть два отношения один ко многим, а не один два ко многим.

0 голосов
/ 20 августа 2017

Будет ли это работать:

@OneToMany
@JoinFormula(value = "SELECT g.id FROM game g WHERE g.homeTeam = id or g.awayTeam=id") 
private Set<Game> games;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...