Отношения ManyToMany с использованием JPA с провайдером Hibernate не создают первичные ключи - PullRequest
8 голосов
/ 13 августа 2010

Я создал две сущности JPA (Client, InstrumentTraded), используя Hibernate в качестве поставщика, имеющего отношение ManyToMany. После того, как Hibernate сгенерировал таблицы для MySQL, оказалось, что таблица отношений ManyToMany не содержит первичных ключей для двух внешних ключей. Это позволяет дублировать записи в таблице «многие ко многим», что не является желаемым результатом.

Создано таблиц:

client(id,name)  
instrument_traded(id,name)  
client_instrument_traded(FK client_id, FK instrument_traded_id)

Таблица предпочтений:

client_instrument_traded(PK,FK client_id, PK,FK instrument_traded_id)

Сущность:

@Entity
public class Client extends AbstractEntity<Integer> {

    private static final long serialVersionUID = 1L;

    @Basic(optional = false)
    @Column(nullable = false, length = 125)
    private String name;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(joinColumns = {
        @JoinColumn}, inverseJoinColumns = {
        @JoinColumn(name = "instrument_traded_id")}, uniqueConstraints =
    @UniqueConstraint(name = "UK_client_instruments_traded_client_id_instrument_traded_id",
    columnNames = {"client_id", "instrument_traded_id"}))
    @ForeignKey(name = "FK_client_instruments_traded_client_id",
    inverseName = "FK_client_instruments_traded_instrument_traded_id")
    private List<InstrumentTraded> instrumentsTraded;

    public Client() {
    }

    public List<InstrumentTraded> getInstrumentsTraded() {
        return instrumentsTraded;
    }

    public void setInstrumentsTraded(List<InstrumentTraded> instrumentsTraded) {
        this.instrumentsTraded = instrumentsTraded;
    }

    ...
}



@Entity
@Table(uniqueConstraints = {
    @UniqueConstraint(name = "UK_instrument_traded_name", columnNames = {"name"})})
public class InstrumentTraded extends AbstractEntity<Integer> {

    private static final long serialVersionUID = 1L;

    @Basic(optional = false)
    @Column(nullable = false, length = 50)
    private String name;

    @ManyToMany(mappedBy = "instrumentsTraded", fetch = FetchType.LAZY)
    private List<Client> clients;

    public InstrumentTraded() {
    }

    public List<Client> getClients() {
        return clients;
    }

    public void setClients(List<Client> clients) {
        this.clients = clients;
    }

    ...

}

После некоторого исследования кажется, что единственным решением является отображение таблицы соединения с дополнительными столбцами с использованием @OneToMany @IdClass и класса составного первичного ключа, когда мне не нужны дополнительные столбцы. Является ли это единственным решением, кроме того, которое я включил в приведенный выше код, в котором используется @UniqueConstraint с двумя столбцами внешнего ключа в сопоставлении @ManyToMany? Кажется немного нелепым объем работы, необходимый для такого сценария, как этот. Спасибо!

Ответы [ 4 ]

17 голосов
/ 14 сентября 2011

У меня была похожая проблема.Все, что я сделал, это то, что я изменил тип коллекции с List на Set:

private List<InstrumentTraded> instrumentsTraded;

на

private Set<InstrumentTraded> instrumentsTraded;

И каким-то образом Hibernate теперь генерирует первичные ключи для таблицы соединения.

6 голосов
/ 22 мая 2011

Вот способ решения проблемы:

Client.java:

 @ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
 @JoinTable(
        joinColumns = {@JoinColumn(name = "client_id")},
        inverseJoinColumns = {@JoinColumn(name = "instrument_traded_id")},
        uniqueConstraints = {@UniqueConstraint(
            columnNames = {"client_id", "instrument_traded_id"})}
)
 private List<InstrumentTraded> instrumentsTraded;

Это для однонаправленного картирования. Если вы хотите двунаправленное отношение, измените отображение в InstrumentTraded.class на то же самое.

2 голосов
/ 13 августа 2010

Ваше отображение выглядит странно (в частности, joinColumn часть аннотации @JoinTable). Я бы ожидал что-то вроде этого:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
    joinColumns= 
        @JoinColumn(name="CLIENT_ID", referencedColumnName="ID"), 
    inverseJoinColumns=
        @JoinColumn(name="instrument_traded_id", referencedColumnName="ID"),
    uniqueConstraints=
        @UniqueConstraint(
            name="UK_client_instruments_traded_client_id_instrument_traded_id",
            columnNames = {"client_id", "instrument_traded_id"}
        )
)
@ForeignKey(name = "FK_client_instruments_traded_client_id",
inverseName = "FK_client_instruments_traded_instrument_traded_id")
private List<InstrumentTraded> instrumentsTraded;

Но если вы не хотите переопределить значения по умолчанию (и я полагаю, вы это делаете), я бы просто пропустил @JoinTable.

0 голосов
/ 13 августа 2010

Или Разделите ваше @ManyToMany на отношения @OneToMany - @ManyToOne. Смотрите здесь , как вы можете выполнить это отображение

...