Estoy usando una ligera modificación de java.util.RegularEnumSet para tener una EnumSet persistente:
@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
// ...
}
Esta clase es ahora la base para todos mis conjuntos de enumeración:
@Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
public InterestsSet() {
super(InterestsEnum.class);
}
}
Y ese conjunto que puedo usar en mi entidad:
@Entity
public class MyEntity {
// ...
@Embedded
@AttributeOverride(name="elements", [email protected](name="interests"))
private InterestsSet interests = new InterestsSet();
}
Ventajas:
- Trabajar con un seguro tipo y el conjunto de enumeración performant en el código (ver
java.util.EnumSet
para una descripción)
- El conjunto es sólo una columna numérica en la base de datos
- todo es normal APP (sin proveedor específicos tipos personalizados)
- fácil (y corto) declaración de nuevos campos del mismo tipo, en comparación con las otras soluciones
inconvenientes:
- la duplicación de código (
RegularEnumSet
y PersistentEnumSet
son casi lo mismo)
- Usted puede envolver el resultado de
EnumSet.noneOf(enumType)
en su PersistenEnumSet
, declarar AccessType.PROPERTY
y proporcionar dos métodos de acceso que utilizan la reflexión para leer y escribir el campo elements
- Se necesita una clase de conjunto adicional para cada clase enum que debe almacenarse en un conjunto persistente
- Si su proveedor de persistencia lo apoya ts incrustables sin un constructor público, se podría añadir a
@Embeddable
PersistentEnumSet
y soltar el clase extra (... interests = new PersistentEnumSet<>(InterestsEnum.class);
)
- Debe utilizar un
@AttributeOverride
, como se da en mi ejemplo, si usted tiene más de un PersistentEnumSet
en su entidad (de lo contrario, ambos se almacenarían en la misma columna "elementos")
- El acceso de
values()
con reflejo en el constructor no es óptimo (especialmente cuando se mira el rendimiento), pero las otras dos opciones también tienen sus inconvenientes :
- Un implemento ación como
EnumSet.getUniverse()
hace uso de un sun.misc
clase
- Proporcionar la matriz como valores de parámetros tiene el riesgo de que los valores dados no son los correctos
- Sólo las enumeraciones con un máximo de 64 valores son compatibles (es que realmente una ¿retirarse?)
- Usted podría utilizar BigInteger lugar
- No es fácil de utilizar el campo de los elementos en una consulta de criterios o JPQL
- Se podría utilizar operadores binarios o una columna de máscara de bits con las funciones adecuadas, si su base de datos admite que
En caso de que alguien lea esto ahora ... @CollectionOfElements ahora está en desuso, en su lugar use: @ElementCollection –
Puede encontrar una muestra en el contestador de esta pregunta: http://stackoverflow.com/q/3152787/363573 – Stephan
Dado que usted He mencionado Hibernate, pensé que esta respuesta podría haber sido específica del proveedor, pero no creo que sea así a menos que el uso de JoinTable cause problemas en otras implementaciones. Por lo que he visto, creo que debe usarse CollectionTable en su lugar. Eso es lo que usé en mi respuesta y funciona para mí (aunque sí, también estoy usando Hibernate en este momento). – spaaarky21