¿Cuál es la forma más inteligente de lograr que una entidad con un campo de tipo Lista persista?
Command.java
package persistlistofstring;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
@Entity
public class Command implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Basic
List<String> arguments = new ArrayList<String>();
public static void main(String[] args) {
Command command = new Command();
EntityManager em = Persistence
.createEntityManagerFactory("pu")
.createEntityManager();
em.getTransaction().begin();
em.persist(command);
em.getTransaction().commit();
em.close();
System.out.println("Persisted with id=" + command.id);
}
}
Este código produce:
> Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named pu: Provider named oracle.toplink.essentials.PersistenceProvider threw unexpected exception at create EntityManagerFactory:
> oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Local Exception Stack:
> Exception [TOPLINK-30005] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException
> Exception Description: An exception was thrown while searching for persistence archives with ClassLoader: sun.misc.Launcher$AppClassLoader@11b86e7
> Internal Exception: javax.persistence.PersistenceException: Exception [TOPLINK-28018] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EntityManagerSetupException
> Exception Description: predeploy for PersistenceUnit [pu] failed.
> Internal Exception: Exception [TOPLINK-7155] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.ValidationException
> Exception Description: The type [interface java.util.List] for the attribute [arguments] on the entity class [class persistlistofstring.Command] is not a valid type for a serialized mapping. The attribute type must implement the Serializable interface.
> at oracle.toplink.essentials.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:143)
> at oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider.createEntityManagerFactory(EntityManagerFactoryProvider.java:169)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:110)
> at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:83)
> at persistlistofstring.Command.main(Command.java:30)
> Caused by:
> ...
Lamento revivir un hilo antiguo, pero si alguien busca una solución alternativa donde almacene sus listas de cadenas como un campo en su base de datos, así es como lo resolví. Crea un convertidor como este:
Ahora úsalo en tus Entidades así:
En la base de datos, su lista se almacenará como foo; bar; foobar y en su objeto Java obtendrá una lista con esas cadenas.
Espero que esto sea útil para alguien.
fuente
SPLIT_CHAR
ocurrencia en su cadena.Esta respuesta se realizó antes de las implementaciones de JPA2, si está utilizando JPA2, consulte la respuesta de ElementCollection anterior:
Las listas de objetos dentro de un objeto modelo generalmente se consideran relaciones "OneToMany" con otro objeto. Sin embargo, una Cadena no es (por sí misma) un cliente permitido de una relación Uno a Muchos, ya que no tiene una ID.
Por lo tanto, debe convertir su lista de cadenas en una lista de objetos JPA de clase Argumento que contengan un ID y una cadena. Potencialmente, podría usar la Cadena como ID, lo que ahorraría un poco de espacio en su tabla, tanto al eliminar el campo ID como al consolidar filas donde las Cadenas son iguales, pero perdería la capacidad de ordenar los argumentos nuevamente en su orden original (ya que no almacenó ninguna información de pedido).
Alternativamente, puede convertir su lista a @Transient y agregar otro campo (argStorage) a su clase que sea VARCHAR () o CLOB. Luego deberá agregar 3 funciones: 2 de ellas son las mismas y deben convertir su lista de cadenas en una sola cadena (en argStorage) delimitada de manera que pueda separarlas fácilmente. Anote estas dos funciones (que cada una hace lo mismo) con @PrePersist y @PreUpdate. Finalmente, agregue la tercera función que divide el argStorage en la lista de cadenas nuevamente y anótelo @PostLoad. Esto mantendrá su CLOB actualizado con las cadenas cada vez que vaya a almacenar el comando, y mantendrá actualizado el campo argStorage antes de almacenarlo en la base de datos.
Todavía sugiero hacer el primer caso. Es una buena práctica para relaciones reales más tarde.
fuente
Según Java Persistence con Hibernate
Si estabas usando Hibernate, podrías hacer algo como:
Actualización: Nota, esto ahora está disponible en JPA2.
fuente
También podemos usar esto.
fuente
Tuve el mismo problema, así que invertí la posible solución dada, pero al final decidí implementar mi ';' lista separada de cadenas.
así que tengo
De esta forma, la lista es fácilmente legible / editable en la tabla de la base de datos;
fuente
arguments
es una lista de permisos de acceso, entonces tener un carácter especial, aseparator
, podría ser vulnerable a ataques de escalada de privilegios.;
lo que romperá su aplicación.Cuando uso la implementación Hibernate de JPA, descubrí que simplemente declarar el tipo como ArrayList en lugar de List permite que hibernate almacene la lista de datos.
Claramente, esto tiene una serie de desventajas en comparación con la creación de una lista de objetos de entidad. Sin carga diferida, sin capacidad de hacer referencia a las entidades en la lista desde otros objetos, tal vez más dificultad para construir consultas de bases de datos. Sin embargo, cuando se trata de listas de tipos bastante primitivos que siempre querrá buscar con entusiasmo junto con la entidad, este enfoque me parece bien.
fuente
@OneToMany
@ManyToOne
@ElementCollection
, le dará unaCaused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements
excepción al iniciar el servidor. Porque hibernates quiere que uses interfaces de colección.Parece que ninguna de las respuestas exploró las configuraciones más importantes para un
@ElementCollection
mapeo.Cuando asigna una lista con esta anotación y deja que JPA / Hibernate genere automáticamente las tablas, columnas, etc., también utilizará los nombres generados automáticamente.
Entonces, analicemos un ejemplo básico:
@ElementCollection
anotación básica (donde puede definir lo conocidofetch
y lastargetClass
preferencias)@CollectionTable
anotación es muy útil cuando se trata de dar un nombre a la tabla que va a ser generado, así como las definiciones comojoinColumns
,foreignKey
's,indexes
,uniqueConstraints
, etc.@Column
Es importante definir el nombre de la columna que almacenará elvarchar
valor de la lista.La creación de DDL generada sería:
fuente
Ok, sé que es un poco tarde. Pero para esas almas valientes que verán esto a medida que pase el tiempo.
Como está escrito en la documentación :
La parte importante es el tipo que implementa Serializable
Entonces, con mucho, la solución más simple y fácil de usar es simplemente usar ArrayList en lugar de List (o cualquier contenedor serializable):
Sin embargo, recuerde que esto usará la serialización del sistema, por lo que tendrá un precio, como:
Si el modelo de objetos serializados cambia, es posible que no pueda restaurar los datos
Se agrega una pequeña sobrecarga para cada elemento almacenado.
En breve
es bastante simple almacenar banderas o pocos elementos, pero no lo recomendaría para almacenar datos que podrían crecer.
fuente
La respuesta de Thiago es correcta, agregando una muestra más específica a la pregunta, @ElementCollection creará una nueva tabla en su base de datos, pero sin asignar dos tablas, significa que la colección no es una colección de entidades, sino una colección de tipos simples (cadenas, etc. .) o una colección de elementos integrables (clase anotada con @Embeddable ).
Aquí está la muestra para persistir la lista de cadenas
Aquí está la muestra para mantener la lista de objetos personalizados
Para este caso, necesitamos hacer la clase Embeddable
fuente
Aquí está la solución para almacenar un Set usando @Converter y StringTokenizer. Un poco más verifica la solución @ jonck-van-der-kogel .
En su clase de entidad:
StringSetConverter:
fuente
Mi solución para este problema fue separar la clave principal con la clave externa. Si está utilizando eclipse y realizó los cambios anteriores, recuerde actualizar el explorador de la base de datos. Luego, recrea las entidades de las tablas.
fuente