2011-08-30 9 views
7

मुझे अपनी दृढ़ता परत में कई सहयोगियों के साथ समस्या है। मेरा परिदृश्य निम्न है:हाइबरनेट कई से कई एसोसिएशन: बाएं हाथ की ओर संग्रह में तत्व होते हैं, लेकिन दाएं हाथ की ओर संग्रह खाली है

उपयोगकर्ता के पास कई भूमिकाएं हो सकती हैं और भूमिका में कई उपयोगकर्ता संलग्न हो सकते हैं। परीक्षणों के दौरान मुझे एक अजीब व्यवहार का सामना करना पड़ा। मैंने भूमिका वस्तु और कई उपयोगकर्ता वस्तुओं का निर्माण किया। भूमिका प्रत्येक उपयोगकर्ता को सेट की गई थी। इसके बाद उपयोगकर्ताओं को डीएओ का उपयोग करके बचाया गया। फिर उपयोगकर्ता में से एक को यह जांचने के लिए लोड किया जाता है कि उसे उपयोगकर्ता ऑब्जेक्ट को सहेजने से पहले उसे पास किया गया था या नहीं। उपयोगकर्ता पर getRoles() पर कॉल करना दर्शाता है कि भूमिका सही ढंग से सेट की गई थी।

यह जांचने के लिए कि क्या विपरीत दिशा भी काम करती है, भूमिका भूमिका डीएओ का उपयोग करके डेटाबेस से लोड हो जाती है। लेकिन रोल ऑब्जेक्ट पर getUsers() पर कॉल करना केवल एक खाली सेट देता है, हालांकि इसमें इस भूमिका के साथ सभी उपयोगकर्ता शामिल होना चाहिए।

मैंने डेटाबेस तालिका को दो बार चेक किया लेकिन सबकुछ ठीक लगता है। उपयोगकर्ता, भूमिका और user_role तालिका सभी ठीक से भर गए थे।

तो भूमिका वस्तु में कोई उपयोगकर्ता क्यों नहीं है?

मैं निम्नलिखित कक्षाओं के साथ हाइबरनेट और वसंत का उपयोग कर रहा हूं।

उपयोगकर्ता वर्ग

@Entity 
@Table 
public class User extends BusinessObject { 

    ... 

    // Option 1 
    @ManyToMany(fetch = FetchType.LAZY, 
       cascade = CascadeType.ALL, 
       targetEntity=Role.class) 
    @JoinTable(name= "user_role", 
       joinColumns = {@JoinColumn(name="user_id")}, 
       inverseJoinColumns = {@JoinColumn(name="role_id")}) 

    // Option 2 
    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    @JoinTable(name= "user_role", 
        joinColumns = {@JoinColumn(name="user_id")}, 
      inverseJoinColumns = {@JoinColumn(name="role_id")}) 
    private Set<Role> roles = new HashSet<Role>();  

    ... 
} 

भूमिका वर्ग

@Entity 
@Table 
public class Role extends BusinessObject { 
    ... 

    // Option 1 
    @ManyToMany(fetch = FetchType.LAZY, 
       cascade = CascadeType.ALL, 
       mappedBy= "roles", 
       targetEntity = User.class) 

    // Option 2 
    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) 
    @JoinTable(name= "user_role", 
        joinColumns = {@JoinColumn(name="role_id")}, 
        inverseJoinColumns = {@JoinColumn(name="user_id")}) 
    private Set<User> users = new HashSet<User>();   

    ... 
} 

मैं एक JUnit परीक्षण वर्ग में निम्नलिखित कोड का उपयोग कर रहा परीक्षण करने के लिए।

@Test 
public void test(){  
    Transaction trans = sessionFactory.getCurrentSession().beginTransaction(); 

    Role userAdminRole = new Role(); 
    userAdminRole.setName(RoleName.USER_ADMIN); 
    Role userRole = new Role(); 
    userRole.setName(RoleName.USER); 

    User user1 = new User(); 
    user1.setEmail("[email protected]");   
    user1.getRoles().add(userAdminRole); 
    user1.getRoles().add(userRole); 
    userDao.save(user1); 

    User user2 = new User(); 
    user2.setEmail("[email protected]"); 
    user2.getRoles().add(role); 
    userDao.save(user2); 

    User user3 = new User(); 
    user3.setEmail("[email protected]"); 
    user3.getRoles().add(role); 
    userDao.save(user3);    

    trans.commit();  

    User loadedUser = userDao.load(user1.getId()); 

      // Tests passes 
    Assert.assertNotNull(loadedUser); 
    Assert.assertEquals(user1, loadedUser); 

    Set<Role> roles = loadedUser.getRoles();   

      // Tests passes 
    Assert.assertEquals(2, roles.size()); 

    Role loadedUserAdminRole = roleDao.findByName(RoleName.USER_ADMIN); 
    Set<User> users = loadedUserAdminRole.getUsers(); 

    // Test fails: Count is 0 instead of 3 !!!!!!! 
    Assert.assertEquals(3, users.size()); 
} 

अद्यतन

माफ करना, मैं एक बात उल्लेख करना भूल गया। जब मैंने कोड का परीक्षण किया तो मैंने निश्चित रूप से कई वर्ग फ़ाइल में कई बार कई एसोसिएशन को चिह्नित नहीं किया। इसके बजाय मैंने प्रत्येक वर्ग फ़ाइल में विकल्प 1 या विकल्प 2 का उपयोग किया था।

+0

आप कहां शुरू कर रहे हैं और सत्र समाप्त कर रहे हैं (या 'जेपीए में EntityManager')? मुझे संदेह है कि अगर आप 'सेव' के बाद एक सत्र बंद करते हैं और 'लोड' से पहले एक नया शुरू करते हैं, तो चीजें काम करती हैं, क्योंकि यह सत्र कैश की बजाय डेटाबेस से ऑब्जेक्ट खींचती है। –

+0

सत्र पूरी परीक्षा विधि के दौरान खोला गया है। कॉलिंग getSession() को डीएओ की विधि में से एक में हमेशा एक ही सत्र ऑब्जेक्ट देता है जब तक कि उन्हें एक परीक्षण विधि में बुलाया जाता है। – Flo

उत्तर

9

समस्या शायद इस तथ्य से आती है कि आपने दो बार एक ही द्विपक्षीय संघ को मैप किया था। यदि आप एक ही तालिका में शामिल होने या कॉलम में शामिल होने के बारे में दो बार हाइबरनेट को बताते हैं, तो एक समस्या है। एक बिडरेक्शनल एसोसिएशन में, एसोसिएशन के सिरों में से एक को एसोसिएशन को मैप करना चाहिए, और दूसरे को हिब्रनेट को यह बताना होगा कि यह mappedBy विशेषता का उपयोग करके दूसरे छोर के विपरीत है।

चूंकि बहुत से लोग पूरी तरह से सममित हैं, मालिक होने के अंत में से एक का चयन करें (यानी अंत जो एसोसिएशन को मानचित्र बनाता है, और इस प्रकार @JoinTable एनोटेशन है)।दूसरी तरफ सिर्फ उलटा है, और इस प्रकार @JoinTable एनोटेशन नहीं है, लेकिन mappedBy विशेषता है।

उदाहरण:

@Entity 
@Table 
public class User extends BusinessObject { 

    ... 

    // This end is the owner of the association 
    @ManyToMany 
    @JoinTable(name= "user_role", 
       joinColumns = {@JoinColumn(name="user_id")}, 
       inverseJoinColumns = {@JoinColumn(name="role_id")}) 
    private Set<Role> roles = new HashSet<Role>();  
    ... 
} 

@Entity 
@Table 
public class Role extends BusinessObject { 
    ... 

    // This end is not the owner. It's the inverse of the User.roles association 
    @ManyToMany(mappedBy = "roles") 
    private Set<User> users = new HashSet<User>();   

    ... 
} 

अतिरिक्त नोट्स:

  • targetEntity के बाद से हाइबरनेट यह Set के जेनेरिक प्रकार के लिए धन्यवाद जानता है, उपयोगी नहीं है। यह उपयोगी होगा अगर सेट Set<SomeInterface>
  • कैस्केड टाइप प्रकार निश्चित रूप से आप नहीं चाहते हैं। क्या आप उपयोगकर्ता को हटाते समय उपयोगकर्ता की सभी भूमिकाओं को हटाना चाहते हैं? इन भूमिकाओं वाले अन्य उपयोगकर्ताओं के साथ क्या होना चाहिए?
  • आपको लगभग हमेशा एक बिडरेक्शनल एसोसिएशन के दोनों सिरों को प्रारंभ करना चाहिए। हाइबरनेट एसोसिएशन को जारी रखने के लिए स्वामी के अंत में (0eविशेषता के बिना अंत) खाते को ध्यान में रखता है।
  • यह सब Hibernate reference documentation में समझाया गया है। इसे पढ़ें: यह उपयोगी जानकारी से भरा है, और समझना मुश्किल नहीं है।
+0

किसी भी कैस्केडिंग घोषणा के बिना जिस तरह से आपने सलाह दी थी, उस संगठन को बदल दिया और दोनों सिरों पर एसोसिएशन भी सेट किया। अब यह उम्मीद की तरह काम करता है। – Flo

2

बिडरेक्शनल से कई सारे संगठनों से निपटने के दौरान आपको एसोसिएशन के दोनों सिरों को बनाए रखना होगा। आपके मामले में, आपको उपयोगकर्ता को भूमिका में भी जोड़ना होगा। उपयोगकर्ता के लिए भूमिका जोड़ना एक द्विदिश संघ की स्थापना के लिए के रूप में आप किताब Java Persistance with Hibernate में पढ़ सकते हैं पर्याप्त नहीं है:

हमेशा की

, एक द्विदिश संघ (की कोई बात नहीं क्या बहुलता) की आवश्यकता है आप के दोनों सिरों द्वारा सेट किए गए संघ।

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