2010-08-13 66 views
7

Tôi đã tạo hai thực thể JPA (Client, InstrumentTraded) sử dụng Hibernate làm nhà cung cấp có mối quan hệ ManyToMany. Sau khi cho phép Hibernate tạo các bảng cho MySQL, có vẻ như bảng quan hệ ManyToMany không chứa các khóa chính cho hai khóa ngoài. Điều này cho phép các bản ghi trùng lặp trong bảng nhiều đến nhiều, không phải là kết quả mong muốn.Mối quan hệ ManyToMany sử dụng JPA với nhà cung cấp Hibernate không tạo khóa chính

Bàn tạo:

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

bảng ưa thích:

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

Đối tượng:

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

    ... 

} 

Sau khi thực hiện một số nghiên cứu có vẻ như giải pháp duy nhất là dành cho mapping a join table with additional columns sử dụng @OneToMany@IdClass và lớp khóa chính hỗn hợp khi tôi không cần thêm cột. Đây có phải là giải pháp duy nhất bên cạnh giải pháp mà tôi đã đưa vào mã bên trên, sử dụng một mã số @UniqueConstraint với hai cột khóa ngoài trên ánh xạ @ManyToMany không? Có vẻ như một chút vô lý về số lượng công việc cần thiết cho một kịch bản chung như thế này. Cảm ơn!

+0

http://stackoverflow.com/questions/1212058/how-to-make-a-composite-primary-key-java-persistence-annotation/6344626#6344626 – steveeen

+0

Cũng đáng để kiểm tra xem bạn vô tình không thêm một bản ghi hai lần, điều này đã xảy ra với tôi, vì vậy 'list.add (x); list.add (x); 'kết quả trùng lặp trong danh sách. – CsBalazsHungary

Trả lời

2

Ánh xạ của bạn trông kỳ lạ (cụ thể là phần joinColumn của chú thích @JoinTable). Tôi mong chờ một cái gì đó như thế này:

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

Nhưng trừ khi bạn muốn ghi đè giá trị mặc định (và tôi đoán bạn làm), tôi sẽ chỉ cần bỏ qua các @JoinTable.

+0

Tôi muốn ghi đè các giá trị mặc định vì nó đa dạng hóa hàm instrument_traded_id (instruments_traded_id). Tôi có một chiến lược đặt tên tùy chỉnh cho biết thêm "_id" nếu nó "_id" không tồn tại ở cuối khóa ngoại. Tôi có thể xóa joinColumns = @ JoinColumn.Bạn có một ví dụ làm việc của ManyToMany tạo khóa chính bao gồm hai khóa ngoài trong bảng ManyToMany? – dukethrash

+0

@dukethrash: 'Bạn có ví dụ làm việc của ManyToMany tạo khóa chính bao gồm hai khóa ngoại trong bảng ManyToMany không?' Đó là hành vi mặc định nếu được chú thích đúng cách. Bạn đã thử mà không có 'joinColumn' (hoặc với phần trên)? –

+0

Có, tôi đã thử của bạn (với ngoại lệ mà referencedColumn thực sự referencedColumnName) và nó vẫn không tạo ra các khóa chính. Tôi thậm chí đã thêm vào sau trên InstrumentTraded chỉ để xem nếu điều đó sẽ thay đổi bất cứ điều gì. @ManyToMany (fetch = FetchType.LAZY, mappedBy = "instrumentsTraded") Danh sách riêng khách hàng; – dukethrash

0

Hoặc Chia @ManyToMany của bạn vào @OneToMany - mối quan hệ @ManyToOne Xem here làm thế nào bạn có thể thực hiện lập bản đồ này

6

Dưới đây là một cách để giải quyết vấn đề:

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; 

Đây là bản đồ một chiều. Nếu bạn muốn có mối quan hệ hai chiều, hãy thay đổi ánh xạ trong InstrumentTraded.class thành giống nhau.

15

Tôi gặp sự cố tương tự. Tất cả tôi đã làm được điều đó tôi đã thay đổi kiểu bộ sưu tập từ sách để Đặt:

private List<InstrumentTraded> instrumentsTraded; 

để

private Set<InstrumentTraded> instrumentsTraded; 

Và bằng cách nào đó Hibernate bây giờ tạo khóa chính cho bảng tham gia.

+0

"Tất cả những điều tuyệt vời đều đơn giản ..." –

+0

Có phải không? Hay chỉ là Java Set làm công việc của nó trên bộ nhớ? – ViniciusPires

+0

Cũng đáng để kiểm tra nếu bạn vô tình không thêm một bản ghi hai lần, điều này xảy ra với tôi, vì vậy 'list.add (x); list.add (x); 'kết quả trùng lặp trong danh sách. – CsBalazsHungary

Các vấn đề liên quan