2009-09-29 39 views
11

Tôi có một tình huống mà tôi cần phải tham gia các bảng trên một đối tượng trong một hệ thống phân cấp lớp ORM trong đó cột kết nối KHÔNG phải là khóa chính của lớp cơ sở. Dưới đây là một ví dụ về việc thiết kế bảng:Làm cách nào để tôi tham gia các bảng trên các cột chính không phải chính trong bảng phụ?

CREATE TABLE APP.FOO 
(
    FOO_ID INTEGER NOT NULL, 
    TYPE_ID INTEGER NOT NULL, 
    PRIMARY KEY(FOO_ID) 
) 

CREATE TABLE APP.BAR 
(
    FOO_ID INTEGER NOT NULL, 
    BAR_ID INTEGER NOT NULL, 
    PRIMARY KEY(BAR_ID), 
    CONSTRAINT bar_fk FOREIGN KEY(FOO_ID) REFERENCES APP.FOO(FOO_ID) 
) 

CREATE TABLE APP.BAR_NAMES 
(
    BAR_ID INTEGER NOT NULL, 
    BAR_NAME VARCHAR(128) NOT NULL, 
    PRIMARY KEY(BAR_ID, BAR_NAME), 
    CONSTRAINT bar_names_fk FOREIGN KEY(BAR_ID) REFERENCES APP.BAR(BAR_ID) 
) 

Và đây là các ánh xạ (getter và setter loại bỏ cho ngắn gọn

@Entity 
@Table(name = "FOO") 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "TYPE_ID", discriminatorType = javax.persistence.DiscriminatorType.INTEGER) 
public abstract class Foo { 
    @Id 
    @Column(name = "FOO_ID") 
    private Long fooId; 
} 

@Entity 
@DiscriminatorValue("1") 
@SecondaryTable(name = "BAR", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "FOO_ID", referencedColumnName = "FOO_ID") }) 
public class Bar extends Foo{ 
    @Column(table = "BAR", name = "BAR_ID") 
    Long barId; 
}  

Làm thế nào tôi có thể thêm các bản đồ cho BAR_NAMES cho rằng nó tham gia cột không FOO_ID, nhưng BAR_ID

tôi đã thử những điều sau đây:?

@CollectionOfElements(fetch = FetchType.LAZY) 
@Column(name = "BAR_NAME") 
@JoinTable(name = "BAR_NAMES", joinColumns = @JoinColumn(table = "BAR", name = "BAR_ID", referencedColumnName="BAR_ID")) 
List<String> names = new ArrayList<String>(); 

Điều này không thành công vì SQL để truy xuất đối tượng Bar cố gắng lấy giá trị BAR_ID từ bảng FOO. Tôi cũng đã cố gắng thay thế các chú thích JoinTable với

@JoinTable(name = "BAR_NAMES", joinColumns = @JoinColumn(name = "BAR_ID")) 

này tạo ra không có lỗi SQL, nhưng cũng lấy không có dữ liệu vì các truy vấn đối với BAR_NAMES đang sử dụng FOO_ID như tham gia giá trị thay vì BAR_ID.

Đối với mục đích thử nghiệm, tôi đã cư DB với các lệnh sau

insert into FOO (FOO_ID, TYPE_ID) values (10, 1); 
insert into BAR (FOO_ID, BAR_ID) values (10, 20); 
insert into BAR_NAMES (BAR_ID, BAR_NAME) values (20, 'HELLO'); 

Nhiều giải pháp mà xuất hiện để làm việc sẽ trả về một bộ sưu tập sản phẩm nào khi nhận được đối tượng Foo cho ID 10 (như trái ngược với một bộ sưu tập có chứa 1 tên)

Trả lời

6

Tôi đã có thể tìm ra giải pháp cho điều này. Nếu bạn ánh xạ lớp Bar như vậy

@Entity 
@DiscriminatorValue("1") 
@SecondaryTable(name = "BAR", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "FOO_ID", referencedColumnName = "FOO_ID") }) 
public class Bar extends Foo { 
    @OneToOne 
    @JoinColumn(table = "BAR", name = "BAR_ID") 
    MiniBar miniBar; 
} 

và thêm các lớp sau

@Entity 
@SqlResultSetMapping(name = "compositekey", entities = @EntityResult(entityClass = MiniBar.class, fields = { @FieldResult(name = "miniBar", column = "BAR_ID"), })) 
@NamedNativeQuery(name = "compositekey", query = "select BAR_ID from BAR", resultSetMapping = "compositekey") 
@Table(name = "BAR") 
public class MiniBar { 
    @Id 
    @Column(name = "BAR_ID") 
    Long barId; 
} 

Sau đó, bạn có thể thêm bất kỳ loại bản đồ bạn muốn lớp MiniBar như thể barId là khóa chính, và sau đó tiếp tục làm cho nó có sẵn trong lớp bên ngoài Bar.

+0

'barId' vẫn được đánh dấu bằng' @ Id', sự khác biệt là gì? – deathangel908

2

Không chắc làm thế nào để làm điều này với JPA/Chú thích, nhưng với bản đồ XML Hibernate file nó sẽ là một cái gì đó như:

<class name="Bar" table="BAR"> 
    <id name="id" type="int"> 
     <column name="BAR_ID"/> 
     <generator class="native"/> 
    </id> 
    <set name="barNames" table="BAR_NAMES"> 
     <!-- Key in BAR_NAMES table to map to this class's key --> 
     <key column="BAR_ID"/> 
     <!-- The value in the BAR_NAMES table we want to populate this set with --> 
     <element type="string" column="BAR_NAME"/> 
    </set> 
</class> 
+0

Tôi tin rằng điều này tương đương với @JoinTable (name = "BAR_NAMES", joinColumns = @JoinColumn (name = "BAR_ID")), không hoạt động vì nó sử dụng giá trị FOO_ID để tham gia bảng BAR_NAMES. – Jherico

+0

Xin lỗi, tôi đã hiểu sai những gì bạn đang nói. Tôi không thể ánh xạ BAR_ID làm khóa chính cho lớp Bar vì nó là con của đối tượng Foo bằng cách sử dụng thừa kế bảng đơn với bảng phụ hoặc sử dụng kế thừa lớp con đã tham gia. – Jherico

2

Bạn sẽ không thể làm những gì bạn muốn. @CollectionOfElements (và @OneToMany, cho rằng vấn đề) là luôn luôn ánh xạ qua khóa chính của chủ sở hữu của chủ sở hữu.

Cách bạn ánh xạ thừa kế Foo/Bar khá lạ - rõ ràng là chúng không nằm trong cùng một bảng; có vẻ như sử dụng JoinedSubclass sẽ là một cách tiếp cận tốt hơn. Hãy nhớ rằng vẫn không giúp bạn lập bản đồ bar_names đến bar_id vì giá trị khóa chính được chia sẻ trong phân cấp (mặc dù tên cột có thể khác nhau đối với lớp con).

Cách thay thế có thể là sử dụng ánh xạ @OneToOne giữa Foo và Bar thay vì kế thừa. Đó là cách duy nhất bạn có thể lập bản đồ bar_names đến bar_id và ánh xạ thích hợp nhất cho cấu trúc bảng của bạn (mặc dù, có lẽ, không phải cho mô hình miền của bạn).

+0

Trong môi trường sống Foo là một lớp cơ sở cho nhiều lớp con với các loại id khác nhau. Chúng tôi đã sử dụng cả mô hình lớp con đã tham gia và mô hình lớp đơn với các bảng phụ và thấy cả hai đều có điểm mạnh và điểm yếu của chúng. Thay đổi cấu trúc phân cấp không phải là một tùy chọn. – Jherico

+0

Thành thật mà nói, khi bạn tăng thêm cách tiếp cận "từng bảng phân cấp" với bảng phụ, bạn sẽ mất lợi thế duy nhất của nó (hiệu suất hơi nhanh hơn) so với cách tiếp cận "từng bảng một" nhưng điều đó không liên quan đến câu hỏi của bạn. Như tôi đã nói, bạn sẽ không thể ánh xạ bộ sưu tập theo cách bạn muốn mà không thay đổi ánh xạ phân cấp hoặc cấu trúc cơ sở dữ liệu của bạn (ví dụ: 'bar_id' gửi đi và sử dụng' foo_id' làm PK trong toàn bộ hệ thống phân cấp). – ChssPly76

+0

Tham chiếuColumnName cụ thể ở đó để giải quyết loại sự cố này. Nếu tôi tạo một bảng TYPE_NAMES tham gia vào TYPE_ID của bảng FOO, hoạt động như mong đợi. Việc không cho phép ánh xạ trên một cột trong bảng phụ là lỗi hoặc giới hạn thiết kế. Tôi đang cố gắng xác định cái nào. – Jherico

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