Comment conserver une propriété de type List dans JPA?

Quel est le moyen le plus intelligent pour obtenir une entité avec un champ de type Liste persistante?

Commande.java

package persistlistofssortingng; 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 arguments = new ArrayList(); public static void main(Ssortingng[] 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); } } 

Ce code produit:

 > 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 atsortingbute [arguments] on the entity class [class persistlistofssortingng.Command] is not a valid type for a serialized mapping. The atsortingbute 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 persistlistofssortingng.Command.main(Command.java:30) > Caused by: > ... 

Utilisez une implémentation JPA 2: elle ajoute une annotation @ElementCollection, similaire à celle d’Hibernate, qui fait exactement ce dont vous avez besoin. Il y a un exemple ici .

modifier

Comme mentionné dans les commentaires ci-dessous, la mise en œuvre correcte de JPA 2 est

 javax.persistence.ElementCollection @ElementCollection Map collection; 

Voir: http://docs.oracle.com/javaee/6/api/javax/persistence/ElementCollection.html

Cette réponse a été faite avant les implémentations JPA2, si vous utilisez JPA2, consultez la réponse ElementCollection ci-dessus:

Les listes d’objects à l’intérieur d’un object de modèle sont généralement considérées comme des relations “OneToMany” avec un autre object. Cependant, une chaîne n’est pas (par elle-même) un client autorisé pour une relation un-à-plusieurs, car elle ne possède pas d’identifiant.

Vous devez donc convertir votre liste de chaînes en une liste d’objects JPA de classe Argument contenant un ID et une chaîne. Vous pourriez éventuellement utiliser la chaîne comme identifiant, ce qui permettrait d’économiser un peu d’espace dans la table en supprimant le champ ID et en consolidant les lignes où les chaînes sont égales, mais vous perdriez la possibilité de réordonner les arguments dans leur ordre d’origine (car vous n’avez stocké aucune information de commande).

Vous pouvez également convertir votre liste en @Transient et append un autre champ (argStorage) à votre classe, à savoir VARCHAR () ou CLOB. Vous devrez ensuite append 3 fonctions: 2 d’entre elles sont identiques et doivent convertir votre liste de chaînes en une seule chaîne (dans argStorage) délimitée de manière à pouvoir les séparer facilement. Annotez ces deux fonctions (qui font la même chose) avec @PrePersist et @PreUpdate. Enfin, ajoutez la troisième fonction qui divise à nouveau l’argStorage dans la liste des chaînes et annotez-la @PostLoad. Cela gardera votre CLOB mis à jour avec les chaînes chaque fois que vous allez stocker la commande et gardez le champ argStorage mis à jour avant de le stocker dans la firebase database.

Je suggère toujours de faire le premier cas. C’est une bonne pratique pour de vraies relations plus tard.

Selon Java Persistence avec Hibernate

mise en correspondance de collections de types de valeur avec des annotations […]. Au moment de l’écriture, il ne fait pas partie de la norme Java Persistence

Si vous utilisiez Hibernate, vous pourriez faire quelque chose comme:

 @org.hibernate.annotations.CollectionOfElements( targetElement = java.lang.Ssortingng.class ) @JoinTable( name = "foo", joinColumns = @JoinColumn(name = "foo_id") ) @org.hibernate.annotations.IndexColumn( name = "POSITION", base = 1 ) @Column(name = "baz", nullable = false) private List arguments = new ArrayList(); 

Mise à jour: Notez que ceci est maintenant disponible dans JPA2.

J’ai eu le même problème, j’ai donc investi la solution possible, mais à la fin j’ai décidé de mettre en place mon ‘;’ liste séparée de chaîne.

donc j’ai

 // a ; separated list of arguments Ssortingng arguments; public List getArguments() { return Arrays.asList(arguments.split(";")); } 

De cette façon, la liste est facilement lisible / modifiable dans la table de firebase database;

Lors de l’utilisation de l’implémentation Hibernate de JPA, j’ai constaté que la simple déclaration du type en tant que ArrayList au lieu de List permet d’hibernate pour stocker la liste des données.

De toute évidence, cela présente un certain nombre d’inconvénients par rapport à la création d’une liste d’objects Entity. Pas de chargement paresseux, pas de possibilité de référencer les entités de la liste à partir d’autres objects, peut-être plus de difficulté à construire des requêtes de firebase database. Cependant, lorsque vous traitez avec des listes de types assez primitifs que vous voudrez toujours récupérer avec l’entité, cette approche me semble bien.

 @Entity public class Command implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) Long id; ArrayList arguments = new ArrayList(); } 

Nous pouvons aussi l’utiliser.

 @Column(name="arguments") @ElementCollection(targetClass=Ssortingng.class) private List arguments; 

Ok je connais son peu de retard. Mais pour les braves qui verront cela avec le temps.

Comme écrit dans la documentation :

@Basic: Le type de mappage le plus simple vers une colonne de firebase database. L’annotation de base peut être appliquée à une propriété persistante ou à une variable d’instance de l’un des types suivants: types primitifs Java, […] énumérations et tout autre type implémentant java.io.Serializable.

La partie importante est le type qui implémente Serializable

Ainsi, la solution la plus simple et la plus facile à utiliser est de simplement utiliser ArrayList au lieu de List (ou tout conteneur sérialisable):

 @Basic ArrayList lovedColors; @Basic ArrayList catNames; 

Rappelez-vous cependant que cela utilisera la sérialisation du système, donc cela viendra avec un certain prix, tel que:

  • si le modèle d’object sérialisé change, il se peut que vous ne puissiez pas restaurer les données

  • un petit surcoût est ajouté pour chaque élément stocké.

En bref

Il est assez simple de stocker des drapeaux ou quelques éléments, mais je ne le recommanderais pas pour stocker des données qui pourraient grossir.

Désolé de faire revivre un ancien thread mais si quelqu’un cherchait une solution alternative où vous stockez vos listes de chaînes comme un seul champ dans votre firebase database, voici comment j’ai résolu ce problème. Créez un convertisseur comme celui-ci:

 import java.util.Arrays; import java.util.List; import javax.persistence.AtsortingbuteConverter; import javax.persistence.Converter; @Converter public class SsortingngListConverter implements AtsortingbuteConverter, Ssortingng> { private static final Ssortingng SPLIT_CHAR = ";"; @Override public Ssortingng convertToDatabaseColumn(List ssortingngList) { return Ssortingng.join(SPLIT_CHAR, ssortingngList); } @Override public List convertToEntityAtsortingbute(Ssortingng ssortingng) { return Arrays.asList(ssortingng.split(SPLIT_CHAR)); } } 

Maintenant, utilisez-le sur vos entités comme ceci:

 @Convert(converter = SsortingngListConverter.class) private List yourList; 

Dans la firebase database, votre liste sera stockée sous la forme foo; bar; foobar et dans votre object Java, vous obtiendrez une liste avec ces chaînes.

J’espère que cela est utile à quelqu’un.

Mon correctif pour ce problème était de séparer la clé primaire avec la clé étrangère. Si vous utilisez eclipse et apportez les modifications ci-dessus, n’oubliez pas de rafraîchir l’explorateur de firebase database. Recréez ensuite les entités à partir des tables.

La réponse de Thiago est correcte, ajoutant un échantillon plus spécifique à la question, @ElementCollection créera une nouvelle table dans votre firebase database, mais sans mapper deux tables, cela signifie que la collection n’est pas une collection d’entités, mais une collection de types simples .) ou une collection d’éléments intégrables (classe annotée avec @Embeddable ).

Voici la liste des exemples à conserver de Ssortingng

 @ElementCollection private Collection options = new ArrayList(); 

Voici l’exemple de la liste d’ object persistant de l’ object personnalisé

 @Embedded @ElementCollection private Collection carList = new ArrayList(); 

Pour ce cas, nous devons rendre la classe Embeddable

 @Embeddable public class Car { }