2010-08-08 25 views
5

Tôi có một vài lớp mô hình miền trong ứng dụng web của tôi có mối quan hệ phân cấp với chính chúng. Một ví dụ về một là cấu trúc danh mục phân cấp được sử dụng để phân loại các bài đăng của người dùng.EclipseLink @MappedSuperclass và generics

Có một số logic liên quan đến bản chất phân cấp của các lớp này phổ biến. Vì vậy, tôi đã cố gắng chuyển logic thành một lớp siêu lớp được chú thích chung của lớp @MappedSuperclass.

Cái gì như:

@MappedSuperclass 
public abstract class HierarchicalBaseEntity<N extends HierarchicalBaseEntity<N>> extends BaseEntity { 

@ManyToOne(optional=true) 
@JoinColumn(name="parent") 
private N parent; 
private int depth; 

public N getParent() { ... 
public void setParent(N newParent) { ... 

public boolean isRoot() { ... 
public int getDepth() { ... 

public boolean isDescendantOf(N ancestor) { ... 
public static <N extends HierarchicalBaseEntity<N>> N getCommonAncestor(N a, N b) { ... 
public static <N extends HierarchicalBaseEntity<N>> Collection<N> reduceToCommonAncestors(Collection<N> entities) { ... 
} 

Các lớp con sau đó mở rộng HierarchicalBaseEntity cho bản thân như các loại generic N:

@Entity 
public class CategoryBean extends HierarchicalBaseEntity<CategoryBean> { 

Trong Java này tất cả các công trình ra khá sạch sẽ. Nhưng tiếc là EclipseLink không dường như thích chung 'mẹ' lĩnh vực:

private N parent; 

Nó cung cấp cho các ngoại lệ sau đây:

Caused by: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.1.0.v20100614-r7608): org.eclipse.persistence.exceptions.ValidationException 
Exception Description: [class net.timp.yaase.core.model.HierarchicalBaseEntity] uses a non-entity [class java.lang.String] as target entity in the relationship attribute [field parent]. 
at org.eclipse.persistence.exceptions.ValidationException.nonEntityTargetInRelationship(ValidationException.java:1341) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.RelationshipAccessor.getReferenceDescriptor(RelationshipAccessor.java:416) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOneToOneForeignKeyRelationship(ObjectAccessor.java:609) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOwningMappingKeys(ObjectAccessor.java:678) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ManyToOneAccessor.process(ManyToOneAccessor.java:107) 

Tại sao nó phàn nàn về một String phi thực thể?

Là một thử nghiệm tôi đã cố gắng loại bỏ các Generics và chỉ có đồng ruộng cha mẹ được định nghĩa là:

private HierarchicalBaseEntity parent; 

Nếu không có Generics, EclipseLink cho ngoại lệ này:

Caused by: Exception [EclipseLink-7250] (Eclipse Persistence Services - 2.1.0.v20100614-r7608): org.eclipse.persistence.exceptions.ValidationException 
Exception Description: [class net.timp.yaase.core.model.OnymBean] uses a non-entity [class net.timp.yaase.core.model.HierarchicalBaseEntity] as target entity in the relationship attribute [field parent]. 
at org.eclipse.persistence.exceptions.ValidationException.nonEntityTargetInRelationship(ValidationException.java:1341) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.RelationshipAccessor.getReferenceDescriptor(RelationshipAccessor.java:416) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOneToOneForeignKeyRelationship(ObjectAccessor.java:609) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ObjectAccessor.processOwningMappingKeys(ObjectAccessor.java:678) 
at org.eclipse.persistence.internal.jpa.metadata.accessors.mappings.ManyToOneAccessor.process(ManyToOneAccessor.java:107) 

Đúng HierarchicalBaseEntity của nó không phải là một Thực thể trong cả hai trường hợp, là một @MappedSuperclass .. nhưng có cách nào để làm điều này với Generics hay không? Có vẻ như bạn không thể có một trường trong lớp @MappedSuperclass tham chiếu đến một trong các lớp con của nó.

+0

Điều này có vẻ bằng cách nào đó * tương tự * với http://forums.sun.com/thread.jspa?threadID=5268944 (nhưng vấn đề liên quan đã được khắc phục). Bạn có thể thử với nhà cung cấp khác không? –

Trả lời

3

Vấn đề là khi sử dụng Generics làm loại trường cho mối quan hệ EclipseLink không thể biết loại mục tiêu là gì cho đến khi thời gian chạy thực tế được kiểm tra. Vì vậy, ánh xạ sẽ phải được tạo động trong thời gian chạy và điều này không được hỗ trợ. Bạn có thể tiếp tục sử dụng Generic SuperClass nhưng điều này sẽ yêu cầu di chuyển trường đến các thực thể mà chúng có kiểu được xác định sau đó có các getters/setters nội bộ trừu tượng cho các trường đó trả về đối tượng mà các phương thức chung sẽ gọi là đúc loại chung. Covoluted nhưng nó sẽ cho phép cho Generic MappedSuperclass.

+0

Hi Gordon, Cảm ơn câu trả lời của bạn. Tôi sẽ thử đề xuất của bạn về việc đưa các trường vào các lớp con .. Tôi có thể thấy nó hoạt động như thế nào. Tôi hiện đang có giao diện HierarchicalEntity và lớp 'helper' tĩnh với logic. Tác phẩm, nhưng nó không sạch như tôi muốn. Tôi đã tự hỏi nếu @AssociationOverride có thể được sử dụng để xác định lại các hiệp hội trong một số cách .. –

+0

Thật không may trong trường hợp này vấn đề là với các loại thuộc tính. @AssociationOverrides được sử dụng để thay đổi thông tin cơ sở dữ liệu nhưng không có thuộc tính để chỉ định loại mục tiêu. –

+0

Xin chào Gordon, tôi không thể tìm thấy một giải pháp sạch hơn những gì bạn đã đề xuất để thực hiện một siêu lớp cho logic chung với getters trừu tượng. Vì vậy, bạn nhận được phiếu bầu của tôi. BTW. Bạn có biết nếu điều này là có thể trong bất kỳ JPA implemetations hoặc là một phần của JPA spec? –

-1

Các nhà cung cấp khác có hỗ trợ kiểu chung chung trong một mối quan hệ lâu dài là OpenJPA . Giả định OpenJPA tạo ra là trường kiểu generic là một kiểu liên tục và được chú thích như vậy với chú thích @Type (OpenJPA-specific) @Type.

Chú thích @Type này hoạt động như trình giữ chỗ cho công cụ Lập bản đồ OpenJPA và giữ ánh xạ trong đó tham chiếu là bản sắc liên tục của phiên bản thời gian chạy. Nhiều năm trước, tôi đã viết một blog; Tôi trích dẫn nó ở đây một lần nữa không phải để tự quảng cáo, nhưng hy vọng nó có thể chỉ ra một số con đường để bạn hỗ trợ một cây chung mà không phải đẩy thông tin kiểu cụ thể xuống một hệ thống phân cấp kiểu (và do đó mất đi bản chất của mô hình kiểu chung).