12
votes

JPA Persister des entités avec une autre relation

config

  • EclipLsLink 2.3.2 Li>
  • JPA 2.0 LI>
  • Les entités sont créées automatiquement à partir du schéma DB de NetBeans avec Classes d'entité de la base de données ... EM> Wizard. Li>
  • Les classes de contrôleur sont créées automatiquement à partir de Netbeans avec Cours de contrôleur JPA à partir de classes d'entités ... EM> Wizard Li> ul>

    Version courte de la question forte> p>

    dans un scénario classique, deux tables avec une autre relation. Je crée l'entité mère, puis l'entité enfant et je joins l'enfant à la collection du parent. Lorsque je créer em> (méthode du contrôleur), l'entité mère, je m'attends à ce que l'entité enfant soit créée et associée au parent. Pourquoi ça ne va-t-il pas? P>

    version longue forte> p>

    classe parent p> xxx pré>

    classe enfant xxx pré>

    classe principale p> xxx pré>

    cette classe jette une nullpoinpointException en ligne: périphérique.getNetworkInIncollection (). Ajouter ( NET); code> p>

    Le système sait qu'il existe une nouvelle entité périphérique code> et il a un élément net code> dans sa collection. Je m'attendais à écrire périphérique code> dans dB, d'obtenir l'identifiant de l'appareil, joignez-le à net code> et écrivez-le dans dB. P>

    au lieu de cela, j'ai trouvé que ce sont les étapes que je dois faire: p> xxx pré>

    Pourquoi dois-je créer l'enfant lorsque la classe mère connaît son enfant et qu'il devrait le créer pour moi ? strong> p>

    La méthode de création de périphériqueJpacontroller (désolé pour les noms longs dans les champs, ils sont générés automatiquement). P>

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }
    
    public void create(Device device) {
        if (device.getNetworkInterfaceCollection() == null) {
            device.setNetworkInterfaceCollection(new ArrayList<NetworkInterface>());
        }
        EntityManager em = null;
        try {
            em = getEntityManager();
            em.getTransaction().begin();
            Collection<NetworkInterface> attachedNetworkInterfaceCollection = new ArrayList<NetworkInterface>();
            for (NetworkInterface networkInterfaceCollectionNetworkInterfaceToAttach : device.getNetworkInterfaceCollection()) {
                networkInterfaceCollectionNetworkInterfaceToAttach = em.getReference(networkInterfaceCollectionNetworkInterfaceToAttach.getClass(), networkInterfaceCollectionNetworkInterfaceToAttach.getId());
                attachedNetworkInterfaceCollection.add(networkInterfaceCollectionNetworkInterfaceToAttach);
            }
            device.setNetworkInterfaceCollection(attachedNetworkInterfaceCollection);
            em.persist(device);
            for (NetworkInterface networkInterfaceCollectionNetworkInterface : device.getNetworkInterfaceCollection()) {
                Device oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface = networkInterfaceCollectionNetworkInterface.getDeviceId();
                networkInterfaceCollectionNetworkInterface.setDeviceId(device);
                networkInterfaceCollectionNetworkInterface = em.merge(networkInterfaceCollectionNetworkInterface);
                if (oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface != null) {
                    oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface.getNetworkInterfaceCollection().remove(networkInterfaceCollectionNetworkInterface);
                    oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface = em.merge(oldDeviceIdOfNetworkInterfaceCollectionNetworkInterface);
                }
            }
            em.getTransaction().commit();
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }
    


0 commentaires

5 Réponses :


2
votes

Ceci est un comportement connu des membres de données de collecte. La solution la plus simple consiste à modifier votre collection getter à la création de la collection paresseusement.

@XmlTransient
public Collection<NetworkInterface> getNetworkInterfaceCollection() {
    if (networkInterfaceCollection == null) {
        networkInterfaceCollection = new Some_Collection_Type<NetworkInterface>();
    }
    return networkInterfaceCollection;
}


1 commentaires

Ceci est fait dans le DeviceJpacontroller Créer. Voir le si au début. Si la collection est nulle, elle crée une nouvelle et la définit avec la méthode périphérique.setnetNetWorkIncollection . J'ai essayé votre suggestion et je reçois: IllegalArgumentException: une instance d'un PK NULL a été fournie de manière incorrecte à cette recherche.



4
votes

@Dima k est correct dans ce qu'ils disent. Lorsque vous faites cela:

NetworkInterface net = new NetworkInterface("eth0");
getEntityManager().persist(net);


2 commentaires

Vous avez tous deux besoin de l'initialisation de la collection. Mais c'est ma question. Pourquoi dois-je persister deux entités lorsque tout ce dont j'ai besoin est de créer la collection. Le JPA ne devrait-il pas persister toutes les entités de la collection et les associer à la classe mère?


JPA sait sur les entités et quel état ils sont. Donc, créer une entité de périphérique et une entité de réseaux d'interface. JPA saura sur deux entités. Il est de votre responsabilité de le dire la relation entre les deux. Je comprends ce que vous voulez dire que si vous persistez à l'appareil et que vous ajoutez des éléments à sa collection après, que JPA devrait le perserner aussi. Si la collection est remplie lorsque vous PERSIST Le périphérique (ou inversement), le périphérique et ses éléments de collections seront persistés.



0
votes

Cette exception signifie que vous essayez de localiser une entité (probablement par em.getreference ()) qui n'a pas encore été persisté. Vous ne pouvez pas vous être em.getreference () ou em.Find () sur des entités qui n'ont toujours pas de pk.


1 commentaires

Tu as raison. Il essaie de localiser l'identifiant de Net dans un appel Em.GetReference (). L'identifiant est null parce que l'entité n'a pas encore été persistée. S'il vous plaît voir le commentaire à @sotirios Delimanolis Post.



22
votes

J'ai enfin compris la logique derrière la persistance de l'une à de nombreuses entités. Le processus est:

  1. Créer une classe parente
  2. persistez-le
  3. Créer une classe enfant
  4. Enfant associé avec parent
  5. Enfant persist (la collection mère est mise à jour)

    avec code: xxx

    MAINTENANT, je peux trouver un appareil (avec ID par exemple) et je peux obtenir tous ses enfants en utilisant xxx

    dans la classe d'entité de périphérique, que j'ai posté dans la question, il n'y a pas besoin de méthodes addnetworkinterface et removeetwokrinterface . < / p>


1 commentaires

Selon ce que j'ai lu du livre. Cascade = CascadeType.persist doit persister toutes les relations et il vous suffit de mettre à jour une entité, JPA naviguera à travers les relations et mettra à jour les entités associées. Mais ... je ne pouvais pas le faire travailler ...



-1
votes

Pour activer la capacité d'économie sur une relation @onetomany, par exemple xxx

, vous devez dire à votre relation @manytoone qu'il est autorisé à mettre à jour MyTable comme cette mise à jour = true xxx


1 commentaires

Updatable = true, insérable = true sont des valeurs par défaut de toute façon, cela ne résout pas le problème.