Tôi đang sử dụng một sửa đổi nhỏ của java.util.RegularEnumSet để có EnumSet bền vững:
@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");
}
}
}
Lớp này bây giờ là cơ sở cho tất cả các bộ enum của tôi:
@Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
public InterestsSet() {
super(InterestsEnum.class);
}
}
Và tập hợp đó tôi có thể sử dụng trong thực thể của mình:
@Entity
public class MyEntity {
@Embedded
@AttributeOverride(name="elements", column=@Column(name="interests"))
private InterestsSet interests = new InterestsSet();
}
Ưu điểm:
- Làm việc với một loại enum an toàn và hiệu quả được đặt trong mã của bạn (xem
java.util.EnumSet
mô tả)
- Tập hợp chỉ là một cột số trong cơ sở dữ liệu
- mọi thứ đều là JPA thuần túy (không có loại tùy chỉnh cụ thể của nhà cung cấp )
- khai báo dễ dàng (và ngắn gọn) các trường mới cùng loại, so với các giải pháp khác
Hạn chế:
- Mã trùng lặp (
RegularEnumSet
và PersistentEnumSet
gần giống nhau)
- Bạn có thể bao gồm kết quả
EnumSet.noneOf(enumType)
trong của bạn PersistenEnumSet
, khai báo AccessType.PROPERTY
và cung cấp hai phương thức truy cập sử dụng phản chiếu để đọc và ghi elements
trường
- Một lớp tập hợp bổ sung là cần thiết cho mọi lớp enum cần được lưu trữ trong một tập hợp liên tục
- Nếu nhà cung cấp độ bền vững của bạn hỗ trợ các tệp nhúng mà không có hàm tạo công khai, bạn có thể thêm
@Embeddable
vào PersistentEnumSet
và loại bỏ lớp bổ sung ( ... interests = new PersistentEnumSet<>(InterestsEnum.class);
)
- Bạn phải sử dụng một
@AttributeOverride
, như đã cho trong ví dụ của tôi, nếu bạn có nhiều hơn một PersistentEnumSet
trong thực thể của mình (nếu không, cả hai sẽ được lưu trữ vào cùng một cột "phần tử")
- Việc truy cập
values()
với phản xạ trong hàm tạo không phải là tối ưu (đặc biệt là khi xem xét hiệu suất), nhưng hai tùy chọn khác cũng có nhược điểm của chúng:
- Một triển khai như
EnumSet.getUniverse()
sử dụng một sun.misc
lớp
- Việc cung cấp mảng giá trị dưới dạng tham số có nguy cơ các giá trị đã cho không phải là giá trị chính xác
- Chỉ hỗ trợ enums có tối đa 64 giá trị (đó có thực sự là một nhược điểm?)
- Bạn có thể sử dụng BigInteger để thay thế
- Không dễ sử dụng trường phần tử trong truy vấn tiêu chí hoặc JPQL
- Bạn có thể sử dụng toán tử nhị phân hoặc cột bitmask với các chức năng thích hợp, nếu cơ sở dữ liệu của bạn hỗ trợ