Есть ли способ в JPA сопоставить коллекцию перечислений в классе Entity? Или единственное решение - обернуть Enum другим классом домена и использовать его для сопоставления коллекции?
@Entity
public class Person {
public enum InterestsEnum {Books, Sport, etc... }
//@???
Collection<InterestsEnum> interests;
}
Я использую реализацию Hibernate JPA, но, конечно, предпочел бы независимое от реализации решение.
java
jpa
jakarta-ee
Геннадий Шумахер
источник
источник
Ссылка в ответе Энди - отличная отправная точка для сопоставления коллекций «не-Entity» объектов в JPA 2, но не совсем полная, когда дело доходит до сопоставления перечислений. Вот что я придумал вместо этого.
@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; }
источник
@ElementCollection
иCollection<InterestsEnum> interests;
остальное потенциально полезно, но не нужно. Например,@Enumerated(EnumType.STRING)
помещает в вашу базу данных удобочитаемые строки.@Column
«sname
подразумевалось. Я просто хотел прояснить, что подразумевается, когда @Column опущен. И всегда рекомендуется использовать @Enumerated, поскольку порядковый номер - это ужасная вещь по умолчанию. :)@CollectionTable(name="person_interest", joinColumns = {@JoinColumn(name="person_id")})
Я смог сделать это таким простым способом:
@ElementCollection(fetch = FetchType.EAGER) Collection<InterestsEnum> interests;
Активная загрузка требуется, чтобы избежать ошибки инициализации ленивой загрузки, как описано здесь .
источник
Я использую небольшую модификацию java.util.RegularEnumSet, чтобы иметь постоянный EnumSet:
@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 // ... }
Этот класс теперь является базой для всех моих наборов перечислений:
@Embeddable public class InterestsSet extends PersistentEnumSet<InterestsEnum> { public InterestsSet() { super(InterestsEnum.class); } }
И этот набор я могу использовать в своей сущности:
@Entity public class MyEntity { // ... @Embedded @AttributeOverride(name="elements", column=@Column(name="interests")) private InterestsSet interests = new InterestsSet(); }
Преимущества:
java.util.EnumSet
Описание)Недостатки:
RegularEnumSet
иPersistentEnumSet
почти то же самое)EnumSet.noneOf(enumType)
в свойPersistenEnumSet
, объявитьAccessType.PROPERTY
и предоставить два метода доступа, которые используют отражение для чтения и записиelements
поля@Embeddable
кPersistentEnumSet
и понизить дополнительный класс (... interests = new PersistentEnumSet<>(InterestsEnum.class);
)@AttributeOverride
, как указано в моем примере, если у вас более одногоPersistentEnumSet
в вашей сущности (иначе оба будут сохранены в одном столбце "elements")values()
с отражением в конструкторе не является оптимальным (особенно если смотреть на производительность), но два других варианта также имеют свои недостатки:EnumSet.getUniverse()
использованиеsun.misc
классаисточник
tl; dr Краткое решение будет следующим:
@ElementCollection(targetClass = InterestsEnum.class) @CollectionTable @Enumerated(EnumType.STRING) Collection<InterestsEnum> interests;
Длинный ответ заключается в том, что с этими аннотациями JPA создаст одну таблицу, которая будет содержать список InterestsEnum, указывающий на идентификатор основного класса (в данном случае Person.class).
@ElementCollections указывает, где JPA может найти информацию о Enum
@CollectionTable создает таблицу, в которой хранятся отношения от Person до InterestsEnum
@Enumerated (EnumType.STRING) сообщает JPA сохранять Enum как String, может быть EnumType.ORDINAL
источник
Коллекции в JPA относятся к отношениям «один ко многим» или «многие ко многим» и могут содержать только другие сущности. Извините, но вам нужно обернуть эти перечисления в объект. Если подумать, вам все равно понадобится какое-то поле идентификатора и внешний ключ для хранения этой информации. Это если вы не сделаете что-то безумное, например, сохраните список, разделенный запятыми, в String (не делайте этого!).
источник