ConfigJPA utrzymują podmioty z jednego do wielu relacji
- EcliplseLink 2.3.2
- JPA 2.0
- Podmioty są automatycznie tworzone ze schematu db od netbeans z Entity klas z bazy ... Czarodziej.
- Klasy kontrolera są automatycznie tworzone z netbeans z JPA Controller klas z klas Entity ... kreatora
Krótka wersja pytanie
W klasycznym scenariuszu, dwa stoły z jednego do wiele relacji. Tworzę obiekt nadrzędny, a następnie element podrzędny i dołączam dziecko do kolekcji rodzica. Kiedy I utworzyć (metoda kontrolera) nadrzędnej jednostki, oczekuję, że obiekt podrzędny zostanie utworzony i powiązany z rodzica. Dlaczego tak się nie dzieje?
Długa wersja
klasa nadrzędna
@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<NetworkInterface> networkInterfaceCollection;
public Device() {
}
public Device(String name) {
this.name = name;
updated = new Date();
}
// setters and getters...
@XmlTransient
public Collection<NetworkInterface> getNetworkInterfaceCollection() {
return networkInterfaceCollection;
}
public void setNetworkInterfaceCollection(Collection<NetworkInterface> networkInterfaceCollection) {
this.networkInterfaceCollection = networkInterfaceCollection;
}
public void addNetworkInterface(NetworkInterface net) {
this.networkInterfaceCollection.add(net);
}
public void removeNetworkInterface(NetworkInterface net) {
this.networkInterfaceCollection.remove(net);
}
// other methods
}
klasa Child
@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;
}
}
Główna klasa
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);
}
}
Ten cl ass rzuca NullPointerException w linii: device.getNetworkInterfaceCollection().add(net);
System wie, że nie jest to nowa jednostka device
i ma element net
w jego kolekcji. Spodziewałem się, że zapisze w db, device
, otrzyma identyfikator urządzenia, dołącz go do net
i zapisz go w db.
Zamiast tego, znalazłem, że są to kroki muszę zrobić:
deviceController.create(device);
net.setDeviceId(device);
device.getNetworkInterfaceCollection().add(net);
netController.create(net);
Dlaczego muszę stworzyć dziecku, gdy klasa dominująca wie, że to dziecko i powinna stworzyć to dla mnie ?
Metoda tworzenia z DeviceJpaController (przepraszam za długie nazwy w polach, są one generowane automatycznie).
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();
}
}
}
Zgodnie z tym, co przeczytałem z książki. 'cascade = CascadeType.Persist' powinien utrzymywać wszystkie relacje i wystarczy tylko zaktualizować jedną encję, JPA będzie nawigował przez relacje i aktualizował powiązane jednostki. Ale ... Nie mogłem tego zrobić ... –