2012-06-09 45 views
14

Tôi có hai lớp học FooBar. Các bảng trong cơ sở dữ liệu giống như thế này:Tổng hợp khóa chính, khóa ngoài. Tham chiếu đến đối tượng hoặc khóa?

|Foo| 
|id : INT (PK) | bar_id : INT (PK, FK) | 

|Bar| 
|id : INT (PK) | 

Thông thường tôi sẽ lập bản đồ nó như thế này:

@Entity 
public class Bar 
{ 
    @Id 
    @Column(name = "id") 
    private int id; 

    @OneToMany 
    private Set<Foo> foo; 
} 

@Entity 
public class Foo 
{ 
    @EmbeddedId 
    private FooPK key; 

    @MapsId("barId") 
    @ManyToOne 
    @JoinColumn(name = "bar_id", referencedColumnName = "id") 
    private Bar bar; 
} 

@Embeddable 
public class FooPK 
{ 
    @Column(name = "id") 
    private int id; 
    @Column(name = "bar_id") 
    private int barId; 
} 

Tuy nhiên của id trong FooPK đang lỏng lẻo ánh xạ và cần phải được kết nối bằng tay. Tôi muốn một giải pháp mà bản đồ bằng cách sử dụng các đối tượng thay vì id lỏng lẻo. Tôi đã thử các sau nhưng (tất nhiên) nó đã không làm việc, nhưng tôi nghĩ rằng nó mang lại một ý tưởng về những gì tôi muốn đạt được:

@Entity 
public class Bar 
{ 
    @Id 
    @Column(name = "id") 
    private int id; 

    @OneToMany 
    private Set<Foo> foo; 
} 

@Entity 
public class Foo 
{ 
    @EmbeddedId 
    private FooPK key; 

    @MapsId("barId") 
    @ManyToOne 
    @JoinColumn(name = "bar_id", referencedColumnName = "id") 
    @Access(AccessType.FIELD) 
    private Bar getBar() 
    { 
     return key.getBar(); 
    } 
} 

@Embeddable 
public class FooPK 
{ 
    @Column(name = "id") 
    private int id; 

    @Transient 
    private Bar bar; 

    //.... 

    @Column(name = "bar_id") 
    @Access(AccessType.PROPERTY) 
    private int getBarId 
    { 
     return bar.getId(); 
    } 
} 

Một vấn đề khác với các giải pháp sau là các phương pháp trong getBarId()FooPK cần có phương thức setBarId(Int). Việc đặt Object bằng cách sử dụng ID có thể được thực hiện bằng cách truy cập vào lớp truy cập dữ liệu, tuy nhiên điều này (theo ý kiến ​​của tôi) vi phạm sự tách biệt của các lớp nghiệp vụ/miền/dữ liệu.

Vậy phải làm gì? Đi với giải pháp đầu tiên và giữ ids đồng bộ bằng tay hoặc là có một (tốt nhất) thực hành?

Trả lời

23

Đề cập đến các cuộc thảo luận JPA 2: composite primary key classes, làm cho những thay đổi sau đây để các lớp Foo và FooPK:

@Entity 
public class Foo { 

    @EmbeddedId 
    private FooPK key; 

    @MapsId("barId") //references EmbeddedId's property 
    @JoinColumn(name = "bar_id", referencedColumnName = "id") 
    @ManyToOne 
    private Bar bar; 
} 

@Embeddable 
public class FooPK { 

    @Column(name = "id") 
    private int id; 
    @Column(name = "bar_id") 
    private int barId; 
} 

Tôi đề nghị đầu tiên làm cho nó làm việc với truy cập LĨNH VỰC và sau đó áp dụng truy cập HỮU.

Vậy phải làm gì? Đi với giải pháp đầu tiên và giữ cho các id đồng bộ hóa theo cách thủ công hoặc có cách nào khác (tốt nhất) thực hành?

Tự khắc phục sự cố - tạo id tự động.

+0

Vì vậy, đó là ví dụ đầu tiên. Tôi đã thấy rằng đây là 'cách để đi', tôi đã tự hỏi nếu ví dụ thứ hai là một cách sạch hơn. Tôi đoán đó là một không? – siebz0r

+0

@ siebz0r oh, xin lỗi, không nhận thấy ví dụ đầu tiên là như nhau; o. Tôi nghĩ rằng, nó dễ dàng hơn để xem xét PK khi có ID, không được ánh xạ đối tượng. Nếu bạn tìm kiếm bằng FooPK, bạn sẽ chỉ cần các số nguyên chứ không phải các đối tượng với tất cả các thuộc tính không cần thiết. – JMelnik

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