Domanda

Ho un paio di classi del modello di dominio nella mia web app che hanno una relazione gerarchica a se stessi. Un esempio di uno è la struttura gerarchica categoria utilizzata per utenti Classificare messaggi.

V'è una certa logica relativa alla natura gerarchica di queste classi che è comune. Così ho provato a spostare la logica in un @MappedSuperclass generica superclasse annotato.

Qualcosa di simile:

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

Le sottoclassi poi estendere HierarchicalBaseEntity dandosi come il tipo generico N:

@Entity
public class CategoryBean extends HierarchicalBaseEntity<CategoryBean> {

In Java questo funziona tutto molto pulito. Ma purtroppo EclipseLink non sembra piacere il campo generico 'genitore':

private N parent;

Si dà la seguente eccezione:

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)

Perché è lamentarsi di una stringa non-entità?

Come test ho provato a rimuovere i farmaci generici e solo per avere il campo genitore definito come:

private HierarchicalBaseEntity parent;

Senza farmaci generici, EclipseLink ha dato questa eccezione:

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)

La vera HierarchicalBaseEntity suo non è un entità in entrambi i casi, è un @MappedSuperclass .. ma c'è un modo per fare questo con i generici o in altro modo? Sembra che non si può avere un campo nel @MappedSuperclass che i riferimenti uno di esso è sottoclasse.

È stato utile?

Soluzione

Il problema è che quando si utilizza Generics come i tipi di campo per i rapporti EclipseLink non può sapere che cosa il tipo di destinazione è fino al runtime quando l'istanza attuale viene ispezionata. Quindi la mappatura dovrebbe essere creato in modo dinamico in fase di esecuzione e questo non è supportato.

Si potrebbe continuare a utilizzare la superclasse generico, ma ciò richiederebbe lo spostamento del campo per i soggetti, quando avrebbero tipi definiti poi avere astratti interne getter / setter per quei campi che Object ritorno che i metodi generici sarebbero casting al generico genere. Contorto ma sarebbe consentire la MappedSuperclass generico.

Altri suggerimenti

Credo di essere in ritardo, ma persone che cercano la risposta a questo problema (come me) dovrebbe dare un'occhiata a questo: https://bugs.eclipse.org/bugs/show_bug.cgi?id= 312.132

L'altro fornitore che supporta tipo generico in una relazione permanente è OpenJPA . L'assunzione OpenJPA fa è che il campo tipo generico è un tipo persistente e essere annotato come tale con (OpenJPA-specifico) @type annotazione.

Questa annotazione @type funge da segnaposto per il motore OpenJPA Mapping, e tiene una mappatura in cui riferimento è un'identità persistente dell'istanza runtime. Molti anni fa, ho scritto un blog ; Cito qui ancora una volta non per l'auto-promozione, ma sperando che potrebbe indicare alcuni percorsi per voi di sostenere un albero generica senza dover spingere verso il basso le informazioni sul tipo di cemento lungo una gerarchia di tipo (e perdendo così l'essenza del modello di tipo generico a base di ).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top