JPA中是否有一种方法可以在Entity类中映射枚举的集合?还是唯一的解决方案是用另一个域类包装Enum并使用它来映射集合?
@Entity
public class Person {
public enum InterestsEnum {Books, Sport, etc... }
//@???
Collection<InterestsEnum> interests;
}
我正在使用Hibernate JPA实现,但是当然更喜欢与实现无关的解决方案。
JPA中是否有一种方法可以在Entity类中映射枚举的集合?还是唯一的解决方案是用另一个域类包装Enum并使用它来映射集合?
@Entity
public class Person {
public enum InterestsEnum {Books, Sport, etc... }
//@???
Collection<InterestsEnum> interests;
}
我正在使用Hibernate JPA实现,但是当然更喜欢与实现无关的解决方案。
Answers:
使用休眠可以做到
@CollectionOfElements(targetElement = InterestsEnum.class)
@JoinTable(name = "tblInterests", joinColumns = @JoinColumn(name = "personID"))
@Column(name = "interest", nullable = false)
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;
Andy的答案中的链接是映射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
的name
被暗示。我只是想澄清省略@Column时的隐含含义。始终建议使用@Enumerated,因为默认情况下序数是一件很糟糕的事情。:)
@CollectionTable(name="person_interest", joinColumns = {@JoinColumn(name="person_id")})
我使用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
的实体中实体否则,这两个实体都将存储在同一列“元素”中)values()
在构造函数使用with反射不是最佳的(特别是在查看性能时),但是其他两个选项也有其缺点:
EnumSet.getUniverse()
实现利用sun.misc
类tl; dr一个简短的解决方案是:
@ElementCollection(targetClass = InterestsEnum.class)
@CollectionTable
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;
长答案是,使用此批注,JPA将创建一个表,该表将保存指向主类标识符(在本例中为Person.class)的InterestsEnum列表。
@ElementCollections指定JPA在哪里可以找到有关枚举的信息
@CollectionTable创建一个表,该表保存从Person到InterestsEnum的关系
@Enumerated(EnumType.STRING)告诉JPA将Enum保留为String,可以是EnumType.ORDINAL
JPA中的集合是指一对多或多对多关系,并且它们只能包含其他实体。抱歉,但是您需要将这些枚举包装在实体中。如果考虑一下,无论如何,您都需要某种ID字段和外键来存储此信息。除非您做一些疯狂的事情,例如将逗号分隔的列表存储在String中(不要这样做!)。