Qual é a maneira mais inteligente de manter uma entidade com um campo do tipo Lista?
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 produz:
> 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:
> ...
Desculpe reviver um thread antigo, mas se alguém estiver procurando por uma solução alternativa em que você armazene suas listas de strings como um campo no banco de dados, eis como eu resolvi isso. Crie um conversor como este:
Agora use-o em suas entidades como esta:
No banco de dados, sua lista será armazenada como foo; bar; foobar e no seu objeto Java, você obterá uma lista com essas strings.
Espero que isto seja útil para alguém.
fonte
SPLIT_CHAR
ocorrências na sua string.Esta resposta foi feita em implementações anteriores ao JPA2, se você estiver usando o JPA2, consulte a resposta do ElementCollection acima:
As listas de objetos dentro de um objeto de modelo são geralmente consideradas relacionamentos "OneToMany" com outro objeto. No entanto, uma String não é (por si só) um cliente permitido de um relacionamento um para muitos, pois não possui um ID.
Portanto, você deve converter sua lista de Strings em uma lista de objetos JPA da classe Argument que contêm um ID e uma String. Você poderia usar a String como o ID, o que economizaria um pouco de espaço na tabela, removendo o campo ID e consolidando as linhas onde as Strings são iguais, mas você perderia a capacidade de ordenar os argumentos de volta à ordem original. (como você não armazenou nenhuma informação de pedido).
Como alternativa, você pode converter sua lista em @Transient e adicionar outro campo (argStorage) à sua classe que é um VARCHAR () ou um CLOB. Você precisará adicionar três funções: duas delas são iguais e deve converter sua lista de Strings em uma única String (em argStorage) delimitada de uma maneira que você possa separá-las facilmente. Anote essas duas funções (que cada uma faz a mesma coisa) com @PrePersist e @PreUpdate. Por fim, adicione a terceira função que divide o argStorage na lista de Strings novamente e anote-o @PostLoad. Isso manterá seu CLOB atualizado com as seqüências sempre que você for armazenar o comando e o campo argStorage atualizado antes de armazená-lo no banco de dados.
Eu ainda sugiro fazer o primeiro caso. É uma boa prática para relacionamentos reais mais tarde.
fonte
De acordo com a persistência de Java com o Hibernate
Se você estivesse usando o Hibernate, poderia fazer algo como:
Atualização: observe que agora está disponível no JPA2.
fonte
Nós também podemos usar isso.
fonte
Ao usar a implementação do JPA no Hibernate, descobri que simplesmente declarar o tipo como ArrayList em vez de List permite que o hibernate armazene a lista de dados.
Claramente, isso tem várias desvantagens em comparação à criação de uma lista de objetos de entidade. Sem carregamento lento, sem capacidade de referenciar as entidades na lista de outros objetos, talvez com mais dificuldade na construção de consultas ao banco de dados. No entanto, quando você está lidando com listas de tipos bastante primitivos que você sempre desejará buscar junto com a entidade, essa abordagem me parece adequada.
fonte
@OneToMany
@ManyToOne
@ElementCollection
ela abrirá umaCaused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements
exceção na inicialização do servidor. Porque o hibernates quer que você use interfaces de coleção.Eu tinha o mesmo problema, então investi na possível solução, mas no final decidi implementar meu ';' lista separada de String.
então eu tenho
Dessa forma, a lista é facilmente legível / editável na tabela do banco de dados;
fonte
arguments
for uma lista de permissões de acesso, o caractere especial aseparator
poderá ser vulnerável a ataques de escalação de privilégios.;
que interromperá seu aplicativo.Parece que nenhuma das respostas explorou as configurações mais importantes para um
@ElementCollection
mapeamento.Quando você mapeia uma lista com esta anotação e permite que o JPA / Hibernate gere automaticamente as tabelas, colunas, etc., ele também usará nomes gerados automaticamente.
Então, vamos analisar um exemplo básico:
@ElementCollection
anotação básica (onde você pode definir o conhecidofetch
e astargetClass
preferências)@CollectionTable
anotação é muito útil quando se trata de dar um nome para a mesa que vai ser gerado, bem como definições comojoinColumns
,foreignKey
's,indexes
,uniqueConstraints
, etc.@Column
é importante definir o nome da coluna que armazenará ovarchar
valor da lista.A criação DDL gerada seria:
fonte
Ok, eu sei que é um pouco tarde. Mas para aquelas almas corajosas que verão isso com o passar do tempo.
Conforme escrito na documentação :
A parte importante é o tipo que implementa Serializable
Portanto, de longe, a solução mais simples e fácil de usar é simplesmente usar ArrayList em vez de List (ou qualquer contêiner serializável):
Lembre-se, no entanto, de que isso usará a serialização do sistema e, portanto, terá algum preço, como:
se o modelo de objeto serializado mudar, talvez você não consiga restaurar dados
uma pequena sobrecarga é adicionada para cada elemento armazenado.
Em resumo
é bastante simples armazenar sinalizadores ou poucos elementos, mas eu não o recomendaria para armazenar dados que podem crescer muito.
fonte
A resposta de Thiago está correta, adicionando amostra mais específica à pergunta, o @ElementCollection criará uma nova tabela no seu banco de dados, mas sem mapear duas tabelas, significa que a coleção não é uma coleção de entidades, mas uma coleção de tipos simples (Strings, etc. .) ou uma coleção de elementos incorporáveis (classe anotada com @Embeddable ).
Aqui está o exemplo para persistir a lista de String
Aqui está o exemplo para persistir a lista de objetos Personalizados
Nesse caso, precisamos tornar a classe Embeddable
fonte
Aqui está a solução para armazenar um conjunto usando o @Converter e o StringTokenizer. Um pouco mais de verificação na solução @ jonck-van-der-kogel .
Na sua classe de entidade:
StringSetConverter:
fonte
Minha correção para esse problema foi separar a chave primária pela chave estrangeira. Se você estiver usando o eclipse e fez as alterações acima, lembre-se de atualizar o explorador de banco de dados. Em seguida, recrie as entidades das tabelas.
fonte