JPA — @OneToMany с JoinTable

Я надеюсь, что смогу объяснить это ясно с первой попытки. Итак, у меня есть две сущности: Person и Address. У одного человека может быть много адресов, поэтому моя сущность Person состоит из списка адресов. Обратите внимание, что адреса могут быть общими для разных людей, однако мой объект Address не нуждается в ссылке на объект Person. Кроме того, каждый объект Address будет иметь атрибут rank.

Моя структура таблицы выглядит следующим образом:

PERSON (
  person_id,
  etc,
  primary key (person_id)
)

ADDRESS (
  address_id,
  etc,
  primary key (address_id)
)

PERSON_ADDRESS_MAP (
  person_id,
  address_id,
  rank,
  foreign key (person_id) references person (person_id),
  foreign key (address_id) references address (address_id),
  primary key (person_id, address_id, rank)
)

Учитывая вышеизложенное, я не уверен, как аннотировать свой список адресов лично или атрибут ранга в адресе. Я подозреваю, что Person будет выглядеть следующим образом:

@Entity
public class Person {
  @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
  @JoinTable(name="person_address_map", joinColumns=@JoinColumn(name="person_id"), inverseJoinColumns=@JoinColumn(name="address_id") )
  private List<Address> addresses;
  ...
}

Я понятия не имею, как аннотировать rank в объекте Address.

заранее спасибо


person user1491636    schedule 17.07.2013    source источник
comment
В тексте указано, что ранг указан в Address, но в описании таблицы указано, что это PERSON_ADDRESS_MAP. Какой из них верный?   -  person JB Nizet    schedule 17.07.2013
comment
Оба верны. Ранг — это атрибут объекта Address, однако он хранится в таблице соединений, поскольку один адрес для одного человека может иметь другой рейтинг, чем тот же адрес для другого человека. Например, Боб оценивает адрес «А» как свой 1-й адрес, но Мэри (которая живет по тому же адресу) ранжирует «А» как свой второй адрес.   -  person user1491636    schedule 18.07.2013


Ответы (1)


Во-первых, логическая связь между Person и Address — это связь «многие ко многим», поскольку у человека много адресов, а адрес используется многими людьми.

Ранг, говорите вы, есть свойство Адреса. Но для данного адреса ранг может быть 1 (для Боба) или 2 (для Мэри). Это просто показывает (и табличная модель ясно это показывает), что ранг не является свойством адреса.

Итак, решение вашей проблемы простое: вам нужно сопоставить таблицу PERSON_ADDRESS_MAP с сущностью:

public class Person {
    @OneToMany(mappedBy = "person")
    private Set<RankedAddress> rankedAddresses;
}

public class RankedAddress {
    @ManyToOne
    private Person person;

    @ManyToOne
    private Address address;
}

public class Address {
    @OneToMany(mappedBy = "adress")
    private Set<RankedAddress> rankedAddresses;
}

Я также советую вам, как и для всех сущностей, добавить одностолбцовый автоматически сгенерированный идентификатор (и соответствующий столбец) к сущности RankedAddress.

Если ранг является единственным дополнением к таблице соединений и если он используется для содержания индекса каждого адреса в списке адресов человека (т. е. он идет от 0 до N - 1, где N - количество адресов пользователя), то есть альтернатива, которая не заставляет вас сопоставлять таблицу соединений с сущностью:

public class Person {
    @ManyToMany
    @OrderColumn(name = "rank")
    private List<Address> addresses;
}

Обратите внимание, что значение столбца будет полностью обрабатываться JPA, и оно будет использоваться только для хранения каждого адреса по заданному индексу в списке. Он будет недоступен для запросов, и вы не сможете узнать ранг адреса человека, кроме как получив его индекс в списке.

person JB Nizet    schedule 17.07.2013
comment
Альтернатива была тем, что я искал. Спасибо! - person user1491636; 18.07.2013