枚举的JPA地图集

Gen*_*her 81 java jpa java-ee

在JPA中有一种方法可以在Entity类中映射枚举的集合吗?或者唯一的解决方案是使用另一个域类包装Enum并使用它来映射集合?

@Entity
public class Person {
    public enum InterestsEnum {Books, Sport, etc...  }
    //@???
    Collection<InterestsEnum> interests;
}
Run Code Online (Sandbox Code Playgroud)

我正在使用Hibernate JPA实现,但当然更喜欢实现不可知的解决方案.

小智 108

使用Hibernate你可以做到

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

  • 如果有人现在读了这个... @CollectionOfElements现在已被弃用,而是使用:@ElementCollection (127认同)
  • 您可以在此问题的答案中找到示例:http://stackoverflow.com/q/3152787/363573 (2认同)

spa*_*y21 60

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 可悲的是,一些"管理员"决定删除该答案而不给出任何理由(这里的课程相同).作为参考,它是http://www.datanucleus.org/products/accessplatform_3_0/jpa/orm/one_to_many_collection.html#join_nonpc (4认同)
  • 您真正需要的只是 `@ElementCollection` 和 `Collection&lt;InterestsEnum&gt; 兴趣;` 其余的可能有用但不必要。例如,`@Enumerated(EnumType.STRING)` 将人类可读的字符串放入您的数据库中。 (2认同)
  • 你是对的 - 在这个例子中,你可以依赖于暗示的`@ Column`的`name`.我只是想澄清省略@Column时隐含的内容.并且始终建议@Enumerated,因为序数是默认的可怕的东西.:) (2认同)

meg*_*cio 6

我能够通过以下简单方式完成此任务:

@ElementCollection(fetch = FetchType.EAGER)
Collection<InterestsEnum> interests;
Run Code Online (Sandbox Code Playgroud)

预先加载需要,以避免延迟加载inizializing错误的解释在这里


miz*_*ebr 6

tl;dr 一个简短的解决方案如下:

@ElementCollection(targetClass = InterestsEnum.class)
@CollectionTable
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;
Run Code Online (Sandbox Code Playgroud)

长的答案是,使用此注释,JPA 将创建一个表,该表将保存指向主类标识符(在本例中为 Person.class)的 InterestsEnum 列表。

@ElementCollections 指定 JPA 可以在何处找到有关 Enum 的信息

@CollectionTable 创建保存从 Person 到 InterestsEnum 的关系的表

@Enumerated(EnumType.STRING) 告诉 JPA 将枚举作为字符串持久化,可以是 EnumType.ORDINAL


Tob*_*fke 5

我使用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
  // ...
}
Run Code Online (Sandbox Code Playgroud)

此类现在是我所有枚举集的基础:

@Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
  public InterestsSet() {
    super(InterestsEnum.class);
  }
}
Run Code Online (Sandbox Code Playgroud)

我可以在我的实体中使用的那个集:

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

好处:

  • 使用代码中设置的类型安全且性能良好的枚举(请参阅参考资料以java.util.EnumSet获取描述)
  • 该集合只是数据库中的一个数字列
  • 一切都是普通的JPA(没有提供程序特定的自定义类型
  • 与其他解决方案相比,轻松(简短)声明相同类型的新字段

缺点:

  • 重复代码(RegularEnumSetPersistentEnumSet几乎相同)
    • 您可以将的结果包装在EnumSet.noneOf(enumType)PersistenEnumSet,声明AccessType.PROPERTY并提供两种访问方法,这些方法使用反射来读取和写入elements字段
  • 每个枚举类都需要一个附加的集合类,该类应存储在一个持久性集合中
    • 如果你的持久提供商支持embeddables没有公共构造函数,你可以添加@EmbeddablePersistentEnumSet并删除多余的类(... interests = new PersistentEnumSet<>(InterestsEnum.class);
  • @AttributeOverride如果您PersistentEnumSet的实体中有多个实体,则必须使用如我的示例中给出的,否则两者都将存储在同一列“元素”中)
  • values()在构造函数中使用with反射的访问不是最佳的(特别是在查看性能时),但是其他两个选项也有其缺点:
    • 像这样的EnumSet.getUniverse()实现利用了一个sun.misc
    • 将values数组作为参数提供时,存在给定值不正确的风险
  • 仅支持最多64个值的枚举(这真的有缺点吗?)
    • 您可以改用BigInteger
  • 在条件查询或JPQL中使用elements字段并不容易
    • 如果数据库支持,则可以使用具有适当功能的二进制运算符或位掩码列


归档时间:

查看次数:

59764 次

最近记录:

8 年,5 月 前