7

我的 Web 应用程序中有一些域模型类与它们自身具有层次关系。一个例子是用于对用户发帖进行分类的层次类别结构。

有一些与这些类的层次性质相关的逻辑是常见的。所以我试图将逻辑移动到一个通用的@MappedSuperclass 注释超类中。

就像是 :

@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) { ...
}

然后子类扩展 HierarchicalBaseEntity 将自己作为泛型类型 N:

@Entity
public class CategoryBean extends HierarchicalBaseEntity<CategoryBean> {

在 Java 中,这一切都非常干净。但不幸的是 EclipseLink 似乎不喜欢通用的“父”字段:

private N parent;

它给出了以下例外:

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)

为什么它抱怨非实体字符串?

作为测试,我尝试删除泛型并将父字段定义为:

private HierarchicalBaseEntity parent;

没有泛型,EclipseLink 给出了这个例外:

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)

真正的 HierarchicalBaseEntity 在任何一种情况下都不是实体,是@MappedSuperclass ..但是有没有办法用泛型或其他方式做到这一点?看来您的 @MappedSuperclass 中不能有一个引用它的子类之一的字段。

4

3 回答 3

5

问题是当使用泛型作为关系的字段类型时,EclipseLink 直到运行时检查实际实例时才能知道目标类型是什么。所以映射必须在运行时动态创建,这是不支持的。

您可以继续使用通用超类,但这需要将字段移动到它们将定义类型的实体,然后为那些返回对象的字段具有抽象的内部 getter/setter,通用方法将调用转换为通用类型。令人费解,但它允许通用 MappedSuperclass。

于 2010-08-09T13:14:26.860 回答
1

我想我迟到了,但是寻找这个问题的答案的人(比如我)应该看看这个: https ://bugs.eclipse.org/bugs/show_bug.cgi?id=312132

于 2010-09-17T17:12:21.450 回答
-1

另一个在持久关系中支持泛型类型的提供者是OpenJPA。OpenJPA 所做的假设是泛型类型字段是持久类型,并使用(OpenJPA 特定的)@Type 注释进行注释。

此@Type 注释充当 OpenJPA 映射引擎的占位符,并保存一个映射,其中引用是运行时实例的持久标识。许多年前,我写了一篇博客;我在这里再次引用它不是为了自我推销,而是希望它可以为您指明一些途径来支持泛型树,而不必将具体类型信息下推到类型层次结构中(从而失去基于泛型的类型模型的本质)。

于 2015-03-13T02:44:49.373 回答