2012-06-29 32 views
7

Tôi tự hỏi làm thế nào một lớp trừu tượng với Generics sẽ xử lý với JPA? Tôi có nghĩa là những loại chú thích nào tôi cần cho lĩnh vực này?JPA và generics

xem xét sau đây:

@MappedSuperclass 
public abstract class AbstractMyClass<T> { 
    // What about Strings and Integers? Do I need some kind of @LOB? 
    private T field; 

    public T getField() { 
    return field; 
    } 

    public void setField(T field) { 
    this.field = field; 
    } 
} 

Và sau đó những

@Entity 
@Table(name = "String") 
public class MyStringClass extends AbstractMyClass<String> { 
} 

@Entity 
@Table(name = "Integer") 
public class MyIntegerClass extends AbstractMyClass<Integer> { 
} 
+0

Bạn đang sử dụng triển khai nào? – JMelnik

+0

Hibernate 3.6 với Oracle 10g làm cơ sở dữ liệu. Ngoài ra, tôi tạo ra các bảng thủ công bằng tay. – jaakko

+0

Bạn đang cố gắng đạt được gì ở cấp thiết kế? Điểm của việc có một siêu lớp như thế nào? –

Trả lời

5

JPA là hoàn toàn có thể xử lý đề nghị của bạn, bởi vì xuất hiện chung ở cấp lớp trừu tượng và cho các lớp bê tông của bạn nó có chính xác một giá trị duy nhất cho mỗi lớp. Trong thực tế, JPA sẽ lưu trữ các lớp con của bạn trong một hoặc nhiều bảng, theo @InheritanceStrategy bạn đã chọn và sử dụng cơ chế khác nhau cho điều đó.

Bạn có thể tìm ra cho mình lý do tại sao trường hợp của bạn không phải là một vấn đề, lý luận về cách một ORM có thể tiết kiệm hai lớp trên DB:

  • Bạn có thể lưu trữ MyStringClass và MyIntegerClass trong cùng một bảng, thêm một Discriminator cột để ORM, khi nó tải từ DB, biết constructor nên được gọi.
  • Bạn có thể lưu trữ mọi phân lớp trong nhiều bảng hơn.

gì là không thể, ở phía bên kia, là để xác định một generic

@Entity 
@Table(name = "MyGenericClass") 
public class MyGenericClass<T> { 
    private T t; 
    public MyGenericClass(T t) { 
     this.t=t; 
    } 
} 

Lý do cho điều này là, tại thời gian biên dịch, T được "xóa" vì loại tẩy xoá. Nó được sử dụng tại thời gian biên dịch để xác minh chữ ký và tính chính xác của các loại, nhưng sau đó nó được biến thành một java.lang.Object bên trong JVM. Nếu bạn làm theo cho đến bây giờ, bạn sẽ có thể hiểu như sau:

  • Trong trường hợp của bạn, mỗi lớp con cụ thể của AbstractMyClass có một kiểu T được định nghĩa cho tất cả các trường của lớp. Trong khi thông tin T không được giữ lại trong AbstractMyClass, nó vẫn được giữ lại và duy nhất bên trong các lớp con.
  • Trong trường hợp thứ hai tôi đăng, mỗi trường hợp cụ thể có thể có của MyGenericClass có thể có giá trị khác nhau có thể cho T và do loại xóa thông tin này không được giữ lại.

* Lưu ý: trường hợp thứ hai không thể được JPA xử lý là hoàn toàn hợp lý và nếu bạn rơi vào trường hợp đó, bạn nên tự hỏi câu hỏi về thiết kế của mình. Generics là một công cụ tuyệt vời để thiết kế các lớp linh hoạt có thể xử lý các lớp khác theo kiểu an toàn, nhưng kiểu an toàn là một khái niệm ngôn ngữ lập trình không liên quan gì tới tính kiên trì.


Thêm: bạn có thể sử dụng javap để xem những gì thực sự là xóa. Cất chú thích khỏi MyGenericClass và biên dịch nó.

G:\>javac MyGenericClass.java 

G:\>javap -p MyGenericClass 
Compiled from "MyGenericClass.java" 
public class MyGenericClass extends java.lang.Object{ 
    private java.lang.Object t; 
    public MyGenericClass(java.lang.Object); 
} 
+0

tôi đã cố gắng này và nó tạo ra một ngoại lệ @Entity @Table (name = "MyFoo") public class MyFooClass kéo dài AbstractMyClass {} Nguyên nhân: org.hibernate.MappingException: Không thể xác định loại cho: fukoka.foobar.Foo, tại bảng: MyFoo, cho các cột: [org.hibernate.mapping.Column (field)] – user1885834

-2

Chúng tôi có thể. nếu số T triển khai Serializable

@Entity 
public class IgsSubject extends BasicObject implements Serializable{ 

    private static final long serialVersionUID = -5387429446192609471L; 

@MappedSuperclass 
public class IgsBasicLog<T> extends BasicObject { 

    @ManyToOne 
    @JoinColumn(name = "ITEM_ID") 
    private T item; 

@Entity 
public class IgsLogA extends IgsBasicLog<IgsSubject> implements Serializable { 
    private static final long serialVersionUID = -8207430344929724212L; 
} 
+0

mã khác giải thích ... – Raymond

+0

Hãy giải thích tại sao 'T' cần triển khai' Seralizable' vì imo nó cần để mở rộng loại thực thể. –