2009-05-05 35 views
10

Tôi có hai lớp thực thể chú thích theo cách sauSaving hai chiều ManyToMany

@Entity 
class A { 
    @ManyToMany(mappedBy="A", cascade=CascadeType.ALL) 
    private List<B> b; 
.. 
} 

@Entity 
class B { 
    @ManyToMany(cascade=CascadeType.ALL) 
    private List<A> a; 
.. 
} 

Nếu tôi lưu trữ một thể hiện của lớp 'B', quan hệ được lưu trữ trong cơ sở dữ liệu và các getter trong lớp học 'A' sẽ trả về tập con của B. Tuy nhiên, nếu tôi thay đổi danh sách các Bs trong 'A', các thay đổi không được lưu trữ trong cơ sở dữ liệu?

Câu hỏi của tôi là, làm thế nào tôi có thể thực hiện để các thay đổi trong cả hai lớp được "xếp tầng" với lớp khác?

EDIT: Tôi đã thử các biến thể khác nhau của việc loại bỏ tham số mappedBy và xác định một JoinTable (và cột), nhưng tôi không thể tìm thấy kết hợp chính xác.

+0

nào thực hiện JPA bạn đang sử dụng? –

Trả lời

16

Câu trả lời ngắn nhất có vẻ là bạn không thể và điều đó có ý nghĩa. Trong một liên kết nhiều-nhiều-hai chiều một bên phải là chủ và được sử dụng để duy trì các thay đổi đối với bảng nối liền bên dưới. Vì JPA sẽ không duy trì cả hai bên của hiệp hội, bạn có thể kết thúc với một tình huống bộ nhớ mà không thể được nạp lại khi được lưu trữ trong cơ sở dữ liệu. Ví dụ:

A a1 = new A(); 
A a2 = new A(); 
B b = new B(); 
a1.getB().add(b); 
b.getA().add(a2); 

Nếu trạng thái này có thể được tiếp tục tồn, bạn sẽ kết thúc với các mục sau trong bảng tham gia:

a1_id, b_id 
a2_id, b_id 

Nhưng khi tải, làm thế nào sẽ JPA biết rằng bạn có ý định chỉ cho b biết về a2 và không a1? và những gì về a2 mà không nên biết về b?

Đây là lý do tại sao bạn phải tự duy trì liên kết hai chiều (và làm ví dụ trên không thể truy cập, ngay cả trong bộ nhớ) và JPA sẽ chỉ tồn tại dựa trên trạng thái của một mặt của nó.

0

Bạn đã tryed thêm tham số mappedBy vào lĩnh vực A trong lớp B như vậy

@Entity 
class B { 
    @ManyToMany(cascade=CascadeType.ALL, mappedBy = "b") 
    private List<A> a; 
.. 
} 
+0

Điều này sẽ không hoạt động, nó là infact một parametrization bất hợp pháp. Tham số mappedBy định nghĩa quyền sở hữu của trường và sử dụng tham số đó cho cả hai bộ sưu tập vì thế không thể, vì chúng không thể sở hữu lẫn nhau. –

3

Bạn đã định nghịch đảo tham gia các cột?

@Entity 
class A { 
    @ManyToMany(mappedBy="A", cascade=CascadeType.ALL) 
    private List <B> b; 
    .. 
} 

@Entity 
class B { 
    @ManyToMany 
    @JoinTable (
     name="A_B", 
     joinColumns = {@JoinColumn(name="A_ID")}, 
     inverseJoinColumns = {@JoinColumn(name="B_ID")} 
    ) 
    private List<A> a; 
    .. 
} 

Giả định bảng tham gia có tên A_B có cột A_ID và B_ID.

+0

Tôi cũng đã thử giải pháp này, nhưng không may mắn: ( –

+2

không nên "mappedBy bằng 'a' chữ thường thay vì lớp? – Ced

0

Có thể có một sai lầm nhỏ trong câu trả lời của A_M. Theo tôi nó nên là:

 
    @Entity 
    class B { 
    @ManyToMany 
    @JoinTable (
     name="A_B", 
     joinColumns = {@JoinColumn(name="B_ID")}, 
     inverseJoinColumns = {@JoinColumn(name="A_ID")} 
    ) 
    private List a; 
    .. 
} 
1

Khi mối quan hệ là hai chiều như vậy là các bản cập nhật ứng dụng một bên của mối quan hệ, phía bên kia cũng nên được cập nhật, và được đồng bộ. Trong JPA, như trong Java nói chung, , đó là trách nhiệm của ứng dụng hoặc mô hình đối tượng để duy trì mối quan hệ . Nếu ứng dụng của bạn thêm vào một bên của mối quan hệ , thì nó phải thêm vào phía bên kia.

này có thể được giải quyết thông qua add hoặc thiết lập các phương pháp trong mô hình đối tượng có thể xử lý cả hai mặt của các mối quan hệ, vì vậy các ứng dụng mã không cần phải lo lắng về nó.Có hai cách để thực hiện việc này, bạn chỉ có thể thêm mã bảo trì mối quan hệ vào một bên của mối quan hệ và chỉ sử dụng công cụ đặt từ một bên (chẳng hạn như bảo vệ bên kia) hoặc thêm mã vào cả hai bên và đảm bảo bạn tránh vòng lặp vô hạn.

Nguồn: OneToMany#Getters_and_Setters