Frage

Gibt es eine Möglichkeit in JPA eine Sammlung von Aufzählungen in der Entity-Klasse zuzuordnen? Oder die einzige Lösung ist Enum mit einer anderen Domäne Klasse zu wickeln und es verwendet, um die Sammlung Karte?

@Entity
public class Person {
    public enum InterestsEnum {Books, Sport, etc...  }
    //@???
    Collection<InterestsEnum> interests;
}

Ich bin mit Hibernate JPA-Implementierung, aber natürlich würde die Umsetzung agnostische Lösung bevorzugen.

War es hilfreich?

Lösung

Hibernate Sie tun können,

@CollectionOfElements(targetElement = InterestsEnum.class)
@JoinTable(name = "tblInterests", joinColumns = @JoinColumn(name = "personID"))
@Column(name = "interest", nullable = false)
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;

Andere Tipps

Der Link Antwort in Andys ist ein guter Ausgangspunkt für die Abbildung einer Sammlung von „Nicht-Entity“ Objekte in JPA 2, ist aber nicht ganz vollständig, wenn es um Mapping Aufzählungen kommt. Hier ist, was ich kam mit statt.

@Entity
public class Person {
    @ElementCollection(targetClass=InterestsEnum.class)
    @Enumerated(EnumType.STRING) // Possibly optional (I'm not sure) but defaults to ORDINAL.
    @CollectionTable(name="person_interest")
    @Column(name="interest") // Column name in person_interest
    Collection<InterestsEnum> interests;
}

Ich konnte dies auf diese einfache Weise erreichen:

@ElementCollection(fetch = FetchType.EAGER)
Collection<InterestsEnum> interests;

Eager Laden ist erforderlich, um ein träges Laden zu vermeiden Fehler inizializing wie erklärt hier .

Ich bin mit einer leichten Modifikation von java.util.RegularEnumSet eine persistente EnumSet haben:

@MappedSuperclass
@Access(AccessType.FIELD)
public class PersistentEnumSet<E extends Enum<E>> 
    extends AbstractSet<E> {
  private long elements;

  @Transient
  private final Class<E> elementType;

  @Transient
  private final E[] universe;

  public PersistentEnumSet(final Class<E> elementType) {
    this.elementType = elementType;
    try {
      this.universe = (E[]) elementType.getMethod("values").invoke(null);
    } catch (final ReflectiveOperationException e) {
      throw new IllegalArgumentException("Not an enum type: " + elementType, e);
    }
    if (this.universe.length > 64) {
      throw new IllegalArgumentException("More than 64 enum elements are not allowed");
    }
  }

  // Copy everything else from java.util.RegularEnumSet
  // ...
}

Diese Klasse ist jetzt die Basis für alle meine Enum-Sets:

@Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
  public InterestsSet() {
    super(InterestsEnum.class);
  }
}

Und das Set kann ich in meiner Einheit verwenden:

@Entity
public class MyEntity {
  // ...
  @Embedded
  @AttributeOverride(name="elements", column=@Column(name="interests"))
  private InterestsSet interests = new InterestsSet();
}

Vorteile:

  • Arbeiten mit einer Art sicher und performant Enum Satz in Ihrem Code (siehe java.util.EnumSet für eine Beschreibung)
  • Der Satz ist nur eine numerische Spalte in der Datenbank
  • alles ist klar JPA (kein Anbieter spezifische benutzerdefinierte Typen )
  • einfach (und kurz) Deklaration von neuen Feldern des gleichen Typs, im Vergleich zu den anderen Lösungen

Nachteile:

  • Code-Duplizierung (RegularEnumSet und PersistentEnumSet sind fast gleich)
    • Sie könnten das Ergebnis von EnumSet.noneOf(enumType) in Ihrem PersistenEnumSet wickeln, AccessType.PROPERTY erklären und zwei Zugriffsmethoden bereitzustellen, die Reflektion verwenden, um zu lesen und das elements Feld
    • schreiben
  • Eine zusätzliche Satz-Klasse wird für jede Enum-Klasse benötigt, die in einem dauerhaften Satz gespeichert werden sollen
    • Wenn Ihre Persistenz-Provider Embeddables ohne öffentlichen Konstruktor unterstützt, könnten Sie @Embeddable hinzufügen PersistentEnumSet-and-Drop Extraklasse (... interests = new PersistentEnumSet<>(InterestsEnum.class);)
  • Sie müssen eine @AttributeOverride verwenden, wie in meinem Beispiel gegeben, wenn Sie mehr als eine PersistentEnumSet in Ihrem Unternehmen haben (sonst würden beide auf die gleiche Spalte „Elemente“ gespeichert werden)
  • Der Zugang von values() mit Reflexion im Konstruktor nicht optimal ist (vor allem, wenn sie bei der Aufführung suchen), aber die beiden anderen Optionen haben ihre Nachteile auch:
    • Eine Implementierung wie EnumSet.getUniverse() nutzt eine sun.misc Klasse
    • Bereitstellung der Werte-Array als Parameter das Risiko, dass die angegebenen Werte sind nicht die richtigen sind
    • hat
  • Nur Aufzählungen mit bis zu 64 Werten werden unterstützt (ist das wirklich ein Nachteil?)
    • Sie könnten BigInteger anstelle
  • Es ist nicht einfach, die Elemente Feld in einer Abfrage Kriterien oder JPQL zu verwenden
    • Sie können binäre Operatoren oder eine Bitmaske Spalte mit den entsprechenden Funktionen verwenden, wenn Ihre Datenbank unterstützt, dass

Sammlungen in JPA beziehen sich auf eine Eins-zu-viele oder viele-zu-viele-Beziehungen, und sie können nur enthalten andere Einheiten. Sorry, aber Sie würden brauchen, um diese Aufzählungen in einer Einheit zu wickeln. Wenn man darüber nachdenkt, dann würden Sie irgendeine Art von ID-Feld und Fremdschlüssel benötigen diese Informationen ohnehin zu speichern. Das heißt, wenn Sie etwas verrückt wie Speicher eine durch Kommata getrennte Liste in einem String zu tun (tun dies nicht!).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top