Note that there are some explanatory texts on larger screens.

plurals
  1. POJPA persist entities with one to many relation
    primarykey
    data
    text
    <p>Config</p> <ul> <li>EcliplseLink 2.3.2</li> <li>JPA 2.0</li> <li>The entities are auto created from the db schema from netbeans with <em>Entity Classes from Database...</em> wizard.</li> <li>The controller classes are auto created from netbeans with <em>JPA Controller Classes from Entity Classes...</em> wizard</li> </ul> <p><strong>Short version of question</strong></p> <p>In a classic scenario, two tables with one to many relation. I create the parent entity, then the child entity and I attach the child to the parent's collection. When I <em>create</em> (controller method) the parent entity, I expect the child entity to be created to and associated with parent. Why doesn't it happen?</p> <p><strong>Long version</strong></p> <p>Parent class</p> <pre><code>@Entity @XmlRootElement public class Device implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) private Integer id; @Column(unique=true) private String name; @Temporal(TemporalType.TIMESTAMP) private Date updated; @OneToMany(cascade = CascadeType.ALL, mappedBy = "deviceId") private Collection&lt;NetworkInterface&gt; networkInterfaceCollection; public Device() { } public Device(String name) { this.name = name; updated = new Date(); } // setters and getters... @XmlTransient public Collection&lt;NetworkInterface&gt; getNetworkInterfaceCollection() { return networkInterfaceCollection; } public void setNetworkInterfaceCollection(Collection&lt;NetworkInterface&gt; networkInterfaceCollection) { this.networkInterfaceCollection = networkInterfaceCollection; } public void addNetworkInterface(NetworkInterface net) { this.networkInterfaceCollection.add(net); } public void removeNetworkInterface(NetworkInterface net) { this.networkInterfaceCollection.remove(net); } // other methods } </code></pre> <p>Child class</p> <pre><code>@Entity @Table(name = "NETWORK_INTERFACE") @XmlRootElement public class NetworkInterface implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) private Integer id; private String name; @Temporal(TemporalType.TIMESTAMP) private Date updated; @JoinColumn(name = "DEVICE_ID", referencedColumnName = "ID") @ManyToOne(optional = false) private Device deviceId; public NetworkInterface() { } public NetworkInterface(String name) { this.name = name; this.updated = new Date(); } // setter and getter methods... public Device getDeviceId() { return deviceId; } public void setDeviceId(Device deviceId) { this.deviceId = deviceId; } } </code></pre> <p>Main class</p> <pre><code>public class Main { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("wifi-dbPU"); DeviceJpaController deviceController = new DeviceJpaController(emf); NetworkInterfaceJpaController netController = new NetworkInterfaceJpaController(emf); Device device = new Device("laptop"); NetworkInterface net = new NetworkInterface("eth0"); device.getNetworkInterfaceCollection().add(net); deviceController.create(device); } } </code></pre> <p>This class throws a NullPointerException in line: <code>device.getNetworkInterfaceCollection().add(net);</code></p> <p>The system knows that there is a new entity <code>device</code> and it has an element <code>net</code> in it's collection. I expected it to write <code>device</code> in db, get device's id, attach it to <code>net</code> and write it in db.</p> <p>Instead of this, I found that these are the steps I have to do:</p> <pre><code>deviceController.create(device); net.setDeviceId(device); device.getNetworkInterfaceCollection().add(net); netController.create(net); </code></pre> <p><strong>Why do I have to create the child when the parent class knows it's child and it should create it for me?</strong></p> <p>The create method from DeviceJpaController (sorry for the long names in fields, they are auto generated).</p> <pre><code>public EntityManager getEntityManager() { return emf.createEntityManager(); } public void create(Device device) { if (device.getNetworkInterfaceCollection() == null) { device.setNetworkInterfaceCollection(new ArrayList&lt;NetworkInterface&gt;()); } EntityManager em = null; try { em = getEntityManager(); em.getTransaction().begin(); Collection&lt;NetworkInterface&gt; attachedNetworkInterfaceCollection = new ArrayList&lt;NetworkInterface&gt;(); 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(); } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload