2009-01-06 8 views
64

क्या एपीटी कक्षा के भीतर एनम्स के संग्रह को मानचित्र बनाने के लिए जेपीए में कोई तरीका है? या एकमात्र समाधान एनम को किसी अन्य डोमेन क्लास के साथ लपेटना है और संग्रह को मानचित्र बनाने के लिए इसका उपयोग करना है?एनपीएमएस का जेपीए मानचित्र संग्रह

@Entity 
public class Person { 
    public enum InterestsEnum {Books, Sport, etc... } 
    //@??? 
    Collection<InterestsEnum> interests; 
} 

मैं हाइबरनेट जेपीए कार्यान्वयन का उपयोग कर रहा हूं, लेकिन निश्चित रूप से क्रियान्वयन अज्ञेय समाधान को प्राथमिकता देना पसंद करेंगे।

उत्तर

86

हाइबरनेट का उपयोग कर आप

@CollectionOfElements(targetElement = InterestsEnum.class) 
@JoinTable(name = "tblInterests", joinColumns = @JoinColumn(name = "personID")) 
@Column(name = "interest", nullable = false) 
@Enumerated(EnumType.STRING) 
Collection<InterestsEnum> interests; 
+106

यदि कोई इसे अब पढ़ता है ... @CollectionOfElements अब बहिष्कृत है, इसके बजाय उपयोग करें: @ElementCollection –

+2

आप इस प्रश्न के उत्तरदाता में एक नमूना पा सकते हैं: http://stackoverflow.com/q/3152787/363573 – Stephan

+0

आप हाइबरनेट का उल्लेख किया, मैंने सोचा कि यह जवाब विक्रेता-विशिष्ट हो सकता है लेकिन मुझे नहीं लगता कि यह तब तक नहीं है जब तक कि जॉइनटेबल का उपयोग अन्य कार्यान्वयन में परेशानी का कारण न हो। मैंने जो देखा है, उससे मेरा मानना ​​है कि कलेक्शनटेबल का इस्तेमाल इसके बजाय किया जाना चाहिए। यही कारण है कि मैंने अपने जवाब में उपयोग किया और यह मेरे लिए काम करता है (हालांकि हाँ, मैं अभी भी हाइबरनेट का उपयोग कर रहा हूं।) – spaaarky21

0

जेपीए में संग्रह एक-से-कई या कई से अधिक रिश्तों को संदर्भित करता है और उनमें केवल अन्य संस्थाएं हो सकती हैं। क्षमा करें, लेकिन आपको उन इकाइयों को एक इकाई में लपेटने की आवश्यकता होगी। यदि आप इसके बारे में सोचते हैं, तो आपको इस जानकारी को वैसे भी स्टोर करने के लिए किसी प्रकार के आईडी फ़ील्ड और विदेशी कुंजी की आवश्यकता होगी। ऐसा तब तक होता है जब तक आप स्ट्रिंग में अल्पविराम से अलग सूची को स्टोर करने की तरह कुछ पागल नहीं करते हैं (ऐसा मत करो!)।

+7

यह केवल जेपीए 1.0 के लिए मान्य है। जेपीए 2.0 में आप उपरोक्त दिखाए गए अनुसार एलीमेंट कोलेक्शन एनोटेशन का उपयोग कर सकते हैं। – rustyx

45

एंडी जवाब में लिंक कर सकते हैं जेपीए 2 में "गैर इकाई" वस्तुओं की मैपिंग संग्रह के लिए एक महान शुरुआती बिंदु है, लेकिन काफी जब यह करने के लिए आता पूरा नहीं हुआ है मानचित्रण enums। यहां मैं इसके साथ आया था।

@Entity 
public class Person { 
    @ElementCollection(targetClass=InterestsEnum.class) 
    @Enumerated(EnumType.STRING) // Possibly optional (I'm not sure) but defaults to ORDINAL. 
    @CollectionTable(name="person_interest") 
    @Column(name="interest") // Column name in person_interest 
    Collection<InterestsEnum> interests; 
} 
+3

अफसोस की बात है कि कुछ "व्यवस्थापक" ने बिना किसी कारण के जवाब को हटाने का निर्णय लिया (इसके लिए बराबर पाठ्यक्रम यहाँ)। संदर्भ के लिए यह http://www.datanucleus.org/products/accessplatform_3_0/jpa/orm/one_to_many_collection.html#join_nonpc – DataNucleus

+1

आपको वास्तव में इसकी आवश्यकता है '@ ElementCollection' और' संग्रह <रुचियां> रुचियां; ' बाकी संभावित रूप से उपयोगी लेकिन अनावश्यक है। उदाहरण के लिए '@ अनुमानित (EnumType.STRING) 'आपके डेटाबेस में मानव पठनीय तार डालता है। – CorayThan

+2

आप सही हैं - इस उदाहरण में, आप '@ कॉलम' के नाम पर भरोसा कर सकते हैं। मैं बस स्पष्ट करना चाहता था कि @ कॉलम छोड़ा गया है जब क्या अंतर्निहित है। और @Enumerated हमेशा अनुशंसा की जाती है क्योंकि ऑर्डिनल डिफ़ॉल्ट रूप से एक भयानक चीज है। :) – spaaarky21

3

मैं java.util का मामूली संशोधन का उपयोग कर रहा हूं।RegularEnumSet एक लगातार EnumSet के लिए:

@MappedSuperclass 
@Access(AccessType.FIELD) 
public class PersistentEnumSet<E extends Enum<E>> 
    extends AbstractSet<E> { 
    private long elements; 

    @Transient 
    private final Class<E> elementType; 

    @Transient 
    private final E[] universe; 

    public PersistentEnumSet(final Class<E> elementType) { 
    this.elementType = elementType; 
    try { 
     this.universe = (E[]) elementType.getMethod("values").invoke(null); 
    } catch (final ReflectiveOperationException e) { 
     throw new IllegalArgumentException("Not an enum type: " + elementType, e); 
    } 
    if (this.universe.length > 64) { 
     throw new IllegalArgumentException("More than 64 enum elements are not allowed"); 
    } 
    } 

    // Copy everything else from java.util.RegularEnumSet 
    // ... 
} 

इस वर्ग अब मेरी enum सेट के सभी के लिए आधार है:

@Embeddable 
public class InterestsSet extends PersistentEnumSet<InterestsEnum> { 
    public InterestsSet() { 
    super(InterestsEnum.class); 
    } 
} 

और वह सेट मैं अपने इकाई में उपयोग कर सकते हैं:

@Entity 
public class MyEntity { 
    // ... 
    @Embedded 
    @AttributeOverride(name="elements", [email protected](name="interests")) 
    private InterestsSet interests = new InterestsSet(); 
} 

लाभ:

  • एक प्रकार सुरक्षित और अपने कोड में performant enum सेट के साथ कार्य करना (विवरण के लिए java.util.EnumSet देखें)
  • सेट सिर्फ एक डेटाबेस में संख्यात्मक स्तंभ है
  • सब कुछ है सादा जेपीए (कोई प्रदाता विशिष्ट कस्टम प्रकार)
  • एक ही प्रकार के नए क्षेत्रों के लिए आसान (और कम) घोषणा, अन्य समाधान

कमियां के साथ तुलना में:

  • कोड दोहराव (RegularEnumSet और PersistentEnumSet लगभग समान हैं)
    • आप अपने PersistenEnumSet में EnumSet.noneOf(enumType) का परिणाम लपेट सकता है, AccessType.PROPERTY घोषित करने और जो प्रतिबिंब का उपयोग दो पहुँच तरीकों को पढ़ने के लिए प्रदान करते हैं और elements क्षेत्र लिखने
  • प्रत्येक एनम कक्षा के लिए एक अतिरिक्त सेट क्लास की आवश्यकता होती है जिसे लगातार सेट
    • में संग्रहीत किया जाना चाहिए यदि आपका दृढ़ता प्रदाता समर्थक एक सार्वजनिक निर्माता बिना ts embeddables, आप PersistentEnumSet को @Embeddable जोड़ सकता है और अतिरिक्त वर्ग (... interests = new PersistentEnumSet<>(InterestsEnum.class);)
  • आप एक @AttributeOverride का उपयोग करना चाहिए छोड़, मेरे उदाहरण के रूप में दी है, यदि आप एक से अधिक PersistentEnumSet में मिल गया है आपकी इकाई (अन्यथा दोनों एक ही कॉलम "तत्वों" में संग्रहीत की जाएंगी)
  • कन्स्ट्रक्टर में प्रतिबिंब के साथ values() का उपयोग इष्टतम नहीं है (विशेष रूप से प्रदर्शन को देखते समय), लेकिन दो अन्य विकल्पों में भी उनकी कमी है :
    • एक कार्यान्वयन EnumSet.getUniverse() तरह समझना बनाता है एक sun.misc वर्ग
    • पैरामीटर के रूप में मान सरणी प्रदान के उपयोग जोखिम है जो दिए गए मानों सही लोगों
  • केवल 64 मूल्यों के साथ enums का समर्थन कर रहे नहीं हैं (यह है कि वास्तव में एक दोष?)
    • आप BigInteger इस्तेमाल कर सकते हैं बजाय
  • यह एक मापदंड क्वेरी में तत्वों क्षेत्र का उपयोग करने के लिए आसान नहीं है या JPQL
    • आप द्विआधारी ऑपरेटर या उचित कार्यों के साथ बिटमास्क स्तंभ, इस्तेमाल कर सकते हैं यदि आपके डेटाबेस का समर्थन करता है कि
1

मैं इस सरल तरीके से यह पूरा करने में सक्षम था:

@ElementCollection(fetch = FetchType.EAGER) 
Collection<InterestsEnum> interests; 

here समझाया गया आलसी लोडिंग त्रुटि को रोकने के लिए उत्सुक लोडिंग की आवश्यकता है।

+0

महान काम किया :) –

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