2013-01-02 23 views
11

कॉन्फ़िगजेपीए कई संबंध

  • EcliplseLink 2.3.2
  • जेपीए 2.0
  • करने के लिए एक साथ संस्थाओं जारी रहती संस्थाओं डाटाबेस से इकाई वर्गों के साथ NetBeans से डाटाबेस स्कीमा से बनाए गए ऑटो रहे हैं ... विज़ार्ड।
  • नियंत्रक कक्षाएं ऑटो इकाई वर्गों से जेपीए नियंत्रक वर्ग ... जादूगर

सवाल

के लघु संस्करण एक क्लासिक परिदृश्य में, करने के लिए एक साथ दो तालिकाओं के साथ NetBeans से बनाई गई हैं कई संबंध मैं मूल इकाई बना देता हूं, फिर बच्चा इकाई और मैं बच्चे को अभिभावक के संग्रह में संलग्न करता हूं। जब मैं पैरेंट इकाई (नियंत्रक विधि) बना देता हूं, तो मुझे उम्मीद है कि बाल इकाई को माता-पिता के साथ बनाया और संबद्ध किया जाएगा। ऐसा क्यों नहीं होता?

लांग संस्करण

जनक वर्ग

@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 
} 

बाल वर्ग

@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; 
    } 
} 

मुख्य वर्ग

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); 
    } 
} 

यह सीएल गधा पंक्ति में एक NullPointerException फेंकता है: device.getNetworkInterfaceCollection().add(net);

प्रणाली जानता है एक नई इकाई device है कि वहाँ और यह एक तत्व net है यह संग्रह है में। मुझे उम्मीद है कि यह device डीबी में लिखने के लिए, डिवाइस की आईडी प्राप्त करें, इसे net से संलग्न करें और इसे डीबी में लिखें।

इसके बजाय इस बात का

, मैंने पाया कि इन चरणों का मैं क्या करना है कर रहे हैं:

deviceController.create(device); 
net.setDeviceId(device); 
device.getNetworkInterfaceCollection().add(net); 
netController.create(net); 

क्यों मैं जब जनक वर्ग जानता है कि यह बच्चा है बच्चे पैदा करने के लिए है और यह मेरे लिए यह बनाना चाहिए ?

डिवाइस जेपी कंट्रोलर से निर्माण विधि (फ़ील्ड में लंबे नामों के लिए खेद है, वे ऑटो जेनरेट हैं)।

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(); 
     } 
    } 
} 

उत्तर

21

मुझे अंततः कई इकाइयों में एक के पीछे तर्क को समझ गया। प्रक्रिया है:

  1. माता पिता कक्षा बनाएं
  2. भी बनी रहती है यह
  3. बच्चे कक्षा बनाएं
  4. इसके साथ एसोसिएट बच्चे माता-पिता
  5. है
  6. भी बनी रहती बच्चे (मूल संग्रह अद्यतन किया जाता है)

कोड के साथ:

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");     // 1 
     deviceController.create(device);      // 2 

     NetworkInterface net = new NetworkInterface("eth0"); // 3 
     net.setDeviceId(device.getId());      // 4 
     netController.create(net);       // 5 
     // The parent collection is updated by the above create  
    } 
} 

अब, मैं (उदाहरण के लिए आईडी के साथ) एक युक्ति पा सकते हैं और मैं प्राप्त कर सकते हैं यह सब

Collection<NetworkInterface> netCollection = device.getNetworkInterfaceCollection() 

डिवाइस इकाई वर्ग जो मैं प्रश्न में तैनात इन का उपयोग करके बच्चे है, तरीकों के लिए कोई जरूरत नहीं है addNetworkInterface और removeNetwokrInterface

+1

पुस्तक से जो मैंने पढ़ा है उसके अनुसार। 'कैस्केड = कैस्केड टाइप टाइपर्स' को सभी रिश्तों को जारी रखना चाहिए और आपको केवल एक इकाई को अपडेट करने की आवश्यकता है, जेपीए संबंधों के माध्यम से नेविगेट करेगा और संबंधित इकाइयों को अपडेट करेगा। लेकिन ... मैं इसे काम नहीं कर सका ... –

2

यह संग्रह डेटा सदस्यों का एक ज्ञात व्यवहार है। सबसे आसान समाधान संग्रह संग्रह बनाने के लिए अपने संग्रह गेटर को संशोधित करना है।

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

साथ ही, गेटटर विधि के माध्यम से केवल इस डेटा सदस्य को संदर्भित करना याद रखें।

+0

यह 'DeviceJpaController' में किया जाता है बनाने के लिए है। शुरुआत में देखें। यदि संग्रह शून्य है, तो यह एक नया बनाता है और इसे 'device.setNetworkInterfaceCollection' विधि से सेट करता है। मैंने आपके सुझाव की कोशिश की और मुझे मिलता है: 'अवैध अर्ग्यूमेंट अपवाद: इस खोज ऑपरेशन के लिए एक शून्य पीके का एक उदाहरण गलत तरीके से प्रदान किया गया है।' –

4

@Dima K वे जो कहते हैं उसमें सही है।जब आप ऐसा करते हैं:

Device device = new Device("laptop"); 
    NetworkInterface net = new NetworkInterface("eth0"); 

    device.getNetworkInterfaceCollection().add(net); 
    deviceController.create(device); 

डिवाइस में संग्रह प्रारंभ नहीं किया गया है और इसलिए इसे जोड़ने का प्रयास करते समय आपको एनपीई मिलती है। अपने Device कक्षा में, जब अपने Collection घोषित करने, आप भी यह प्रारंभ कर सकते हैं:

private Collection<NetworkInterface> networkInterfaceCollection = new CollectionType<>(); 

बने के रूप में, अपने पूर्वानुमान सही हैं लेकिन मुझे लगता है निष्पादन गलत है। जब आप अपना डिवाइस बनाते हैं, तो इसे तुरंत जेपीए के साथ लगातार बनाएं (जहां भी आवश्यक हो लेनदेन प्रबंधन करना)।

Device device = new Device("laptop"); 
getEntityManager().persist(device); 

NetworkInterface लिए भी यही करें:

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

अब के बाद से दोनों अपने संस्थाओं कायम कर रहे हैं, तो आप दूसरे से जोड़ सकते हैं।

device.getNetworkInterfaceCollection().add(net);

जेपीए आप किसी भी अन्य बनी रहती है कॉल करने के लिए बिना आराम का ध्यान रखना चाहिए।

+1

आप दोनों संग्रह प्रारंभिकरण के बारे में सही हैं। लेकिन यह मेरा सवाल है।जब मुझे संग्रह बनाना है तो मुझे दो इकाइयों को क्यों जारी रखना होगा। क्या जेपीए संग्रह में सभी इकाइयों को जारी नहीं रखेगा और उन्हें मूल वर्ग के साथ जोड़ना चाहिए? –

+0

जेपीए इकाइयों के बारे में जानता है और वे किस राज्य में हैं। इसलिए डिवाइस इकाई बनाना और नेटवर्कइंटरफेस इकाई बस यही करती है। जेपीए को दो इकाइयों के बारे में पता चल जाएगा। दोनों के बीच संबंध बताने की आपकी ज़िम्मेदारी है। मैं समझता हूं कि आपका क्या मतलब है कि यदि आप डिवाइस को जारी रखते हैं और उसके संग्रह में तत्व जोड़ते हैं, तो जेपीए को भी उनको जारी रखना चाहिए। यदि संग्रह तब होता है जब आप डिवाइस को 'जारी रखते हैं' (या इसके विपरीत) तो डिवाइस और उसके संग्रह तत्व बनाए रखा जाएगा। –

0

यह अपवाद का मतलब है कि आप किसी इकाई को ढूंढने की कोशिश कर रहे हैं (शायद em.getReference() द्वारा) जो अभी तक जारी नहीं है। आप उन संस्थाओं पर em.getReference() या em.find() नहीं कर सकते हैं जिनके पास अभी भी पीके नहीं है।

+0

आप सही हैं। यह नेट के आईडी को em.getReference() कॉल में ढूंढने का प्रयास करता है। आईडी शून्य है क्योंकि इकाई अभी तक जारी नहीं है। @Sotirios Delimanolis पोस्ट पर टिप्पणी देखें। –

-1

@OneToMany संबंध आदि पर सहेजने की क्षमता को सक्षम करने के लिए

@OneToMany(mappedBy="myTable", cascade=CascadeType.ALL) 
private List<item> items; 

तो फिर आप अपने @ManyToOne संबंध को बताने के लिए है कि यह इस updatable तरह mytable अद्यतन करने के लिए अनुमति दी है = true

@ManyToOne @JoinColumn(name="fk_myTable", nullable = false, updatable = true, insertable = true) 
+0

'updatable = true, insertable = true' वैसे भी डिफ़ॉल्ट हैं, इसलिए यह समस्या को ठीक नहीं करता है। –

संबंधित मुद्दे