2013-09-04 12 views
5

में सेट करें मैं एक इकाई है जो डेटाबेस में कुछ बीआईटी फ़ील्ड होते हैं:नक्शा कुछ बूलियन गुण के रूप में enum हाइबरनेट

  • संपादन योग्य
  • needs_review
  • सक्रिय

इन क्षेत्रों को boolean फ़ील्ड के खिलाफ मैब क्लास में हाइबरनेट 3.6.9 संस्करण का उपयोग करके मैप किया गया है। यही कारण है कि मुझे मजबूर करता संस्थाओं में से प्रत्येक सूची के लिए एक इंटरफेस विधि लिखने के लिए मैं प्राप्त करना चाहते हैं:

List<Entity> listEditables(); 
List<Entity> listReviewNeeded(); 
List<Entity> listActives(); 

या उनमें से एक संयोजन को प्राप्त करने के लिए एक सामान्य इंटरफ़ेस विधि लिखें: दूसरी पसंद अधिक से अधिक लग रहा है

List<Entity> listEntities(boolean editables, boolean reviewNeeded, boolean actives); 

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

तो मैंने तय कर लिया कि मैं एक गणन Set के रूप में यह व्यक्त कर सकते हैं:

public enum EntityType{ 
    EDITABLE, REVIEW_NEEDED, ACTIVE 
} 

//That way there's no need to change interface method's signature 
List<Entity> listEntities(Set<EntityType> requiredTypes); 

यह भावना है कि एक गणन मैच मैं क्या हासिल करना चाहते जा रहा है, Entity प्रकार ही होना चाहिए बनाता है अपनी ही Set<EntityType>:

public class Entity{ 
    Set<EntityType> entityTypes; 
} 

हालांकि इसके बजाय मेरे पास मैप किए गए बूलियन हैं जो Set से तार्किक रूप से मेल खाते हैं। फिर मेरा सवाल है, Set<EntityType> entityTypes को उस बीआईटी फ़ील्ड के आधार पर हाइबरनेट में मैप करने का कोई तरीका है या क्या मुझे उस तर्क को अपने आप को boolean के रूप में प्रबंधित करना है?

अद्यतन

उन्हें मैप किया गया करने के बाद के रूप में एक Set, एक सूची एक in खंड का उपयोग कर के लिए क्वेरी नहीं तो यह मेरे नियंत्रक और मॉडल कोड के बीच रूपांतरण के लिए एक अतिरिक्त कदम अर्थ होगा की संभावना का तात्पर्य।

Set<EntityType> typesSet = Sets.newHashSet(EntityType.EDITABLE, EntityType.REVIEW_NEEDED); 
//Obtains a list of every single entity which is EDITABLE or REVIEW_NEEDED 
session.createCriteria(Entity.class).addRestriction(Restrictions.in("entityTypes",typeSet)).list(); 

उत्तर

1

मुझे नहीं लगता कि हाइबरनेट मैपिंग का प्रबंधन करने का तरीका प्रदान करता है जिस तरह से आप वर्णन कर रहे हैं। आप अपना खुद का UserType (https://community.jboss.org/wiki/Java5EnumUserType) बना सकते हैं, लेकिन हर बार जब आप एक नया एनम वैल्यू जोड़ते हैं तो आपको नए क्षेत्र को मैप करने के लिए UserType में तर्क को बदलना होगा।

विकल्प इसे एक से कई रिश्ते में परिवर्तित करना होगा। आपका बिंदु मूल रूप से है कि यदि आप अधिक फ़ील्ड जोड़ना चाहते हैं तो आपको listEntities के हस्ताक्षर को बदलना होगा, लेकिन आपको अपनी तालिका को संशोधित करना होगा।

तो, इसके बजाय आप एक तालिका बना सकते हैं जिसमें आपकी इकाई प्रकार शामिल हों और आपकी इकाई से @ OneToMany` संबंध हो।उदाहरण के लिए:

अपने झंडे को परिभाषित के रूप में आवश्यक:

@Entity 
@Table(name="entity") 
public class Entity implements Serializable { 

    @OneToMany(mappedBy = "entity") 
public Set<EntityType> getEntityTypes() { 
    return entityTypes; 
} 

और एक कई-से-एक Entity लिए:

public enum Flags { 
    EDITABLE, REVIEW_NEEDED, ACTIVE 
} 

EntityType को एक-से-अनेक संबंध बनाएं

@Entity 
@Table(name="entityType") 
public class EntityType implements Serializable { 

    @Id 
    private Integer id; 

@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "ENTITY_ID") 
    private Entity entity; 

    @Enumerated(EnumType.STRING) 
    private Flag entityType; 

    ... 
} 

पीडी: कृपया ध्यान दें कि कोड सिर्फ एक उदाहरण है और पूर्ण नहीं है ई या परीक्षण किया।

+0

मुझे इसके लिए संबंध बनाने की आवश्यकता पर विचार नहीं है। मैं सिर्फ यह जांचूंगा कि क्या मैं 'EnumUserType' के साथ कुछ हासिल कर सकता हूं। धन्यवाद! –

+0

संभावित रूप से आप इसे 'EnumUserType' के साथ प्राप्त कर सकते हैं लेकिन हर बार जब आप एक नया ध्वज जोड़ते हैं तो आपको एक नया बूलियन जोड़ने के लिए डेटाबेस को बदलना होगा, उपयोगकर्ता प्रकार में मैपिंग और अपनी गणना में एक नया मान जोड़ना होगा जबकि अन्य दृष्टिकोण डेटाबेस को बिल्कुल बदलना नहीं होगा, बस नई गणनाएं जोड़ें –

+0

यह वास्तव में महत्वपूर्ण है कि यह इंटरफेस को बनाए रखता है। एक बार यह हासिल करने के बाद मैं केवल हाइबरनेट को बताना चाहता हूं कि enum बुलियन मूल्यों से मेल खाता है। मैं बस 'सेट' में कुछ नए एनम वैल्यू को सहेजने में सक्षम होना चाहता हूं और संबंधित बुलियन वैल्यू को 1 पर सेट करना चाहता हूं। नए मान जोड़ने के लिए मैपिंग को बदलना कोई समस्या नहीं है, यह कुछ सामान्य नहीं होगा। –

1

कुछ दिमागी तूफान के बाद, मैं एक वर्कअराउंड पर गया हूं जिसे मैं दूसरे सबसे अच्छे व्यक्ति को हाइबरनेट में बुलियन के लिए एक enum मानचित्र करने के लिए असंभव माना जाता है।

public class Entity{ 

    private boolean editable; 

    private boolean needsReview; 

    private boolean active; 

    //getters and setters 

} 

मेरे सूची विधि इस रूप में कार्यान्वित किया जाता है:

public List<Entity> listEntities(Set<EntityType> requiredTypes){ 
    Criteria cri = session.createCriteria(Entity.class); 
    if (requiredTypes.contains(EntityType.EDITABLE)){ 
     cri.addRestriction(Restrictions.eq("editable",true)); 
    } 
    if (requiredTypes.contains(EntityType.NEEDS_REVIEW)){ 
     cri.addRestriction(Restrictions.eq("needsReview",true)); 
    } 
    if (requiredTypes.contains(EntityType.ACTIVE)){ 
     cri.addRestriction(Restrictions.eq("active",true)); 
    } 
    return cri.list(); 
} 

बुरा नहीं है, लेकिन अगर यह है कि के साथ जाने के लिए एक ही रास्ता है पता नहीं है इस तरह मैं अपने Entity वर्ग अब लग रहा है है !

+1

पिछले उत्तर में सुझाए गए एक से कई मैपिंग ओवरकिल हैं। आप EntityType enum के [@ElementCollection] (http://stackoverflow.com/questions/416208/jpa-map-collection-of-enums) के साथ एक ही चीज़ प्राप्त कर सकते हैं। इस मैपिंग का उपयोग करके आपके हाइबरनेट कोड को 'Restrictions.in ("झंडे", आवश्यक प्रकार) का उपयोग करके सरलीकृत किया जा सकता है, लेकिन एसक्यूएल क्वेरी धीमी हो जाएगी क्योंकि इसे तालिकाओं में शामिल होने की आवश्यकता है। – Pieter

3

मुझे लगता है कि मेरे पास आपके लिए समाधान है। आप जो रुचि रखते हैं वह एक कंपोजिट यूज़र टाइप है।

एक उदाहरण के रूप में एक इंटएड्रेस संयुक्त उपयोगकर्ता प्रकार का उपयोग करने के लिए मैंने हाल ही में एक 128 बिट आईपीवी 6 पता/IPv4Address ऑब्जेक्ट को उपयोगकर्ता खाता इकाई के अंदर दो 64 बिट लंबी गुणों को मैप करने के लिए लिखा है।

signupIp: InetAddress दो कॉलम (कोई स्तंभ संख्या सीमा या एक जैसे नहीं है) का उपयोग करने की दिशा में मैप किया गया है:

@Columns(columns = {@Column(name = "ip_low", nullable = true), @Column(name = "ip_high", nullable = true)}) 
    private InetAddress signupIp; 

और कार्यान्वयन के दिलचस्प हिस्सा इस तरह दिखता है:

public class InetAddressUserType implements CompositeUserType { 
@Override 
public String[] getPropertyNames() { 
    return new String [] {"ipLow", "ipHigh"}; 
} 

@Override 
public Type[] getPropertyTypes() { 
    return new Type [] { LongType.INSTANCE, LongType.INSTANCE}; 
} 

@Override 
public Object getPropertyValue(Object component, int property) throws HibernateException { 
    if(component != null) 
     return toLong((InetAddress)component)[property]; 
    else 
     return null; 
} 

@Override 
public void nullSafeSet(PreparedStatement st, Object value, int index, 
     SessionImplementor session) throws HibernateException, SQLException { 

    if(value != null) { 
     long [] longs = toLong((InetAddress)value); 
     st.setLong(index, longs[0]); 
     st.setLong(index + 1, longs[1]); 
    } 
    else { 
     st.setNull(index, LongType.INSTANCE.sqlType()); 
     st.setNull(index + 1, LongType.INSTANCE.sqlType()); 
    } 
} 

@Override 
public void setPropertyValue(Object component, int property, Object value) 
     throws HibernateException { 
    throw new RuntimeException("This object is immutable"); 
} 

@Override 
public Class<?> returnedClass() { 
    return InetAddress.class; 
} 

@Override 
public boolean equals(Object x, Object y) throws HibernateException { 
    return x != null ? x.equals(y) : null == y; 
} 

@Override 
public int hashCode(Object x) throws HibernateException { 
    return x.hashCode(); 
} 

@Override 
public Object nullSafeGet(ResultSet rs, String[] names, 
     SessionImplementor session, Object owner) 
     throws HibernateException, SQLException { 
    Long ipLow = rs.getLong(names[0]); 
    if(!rs.wasNull()) { 
     Long ipHigh = rs.getLong(names[1]); 

     try { 
      return fromLong(new long [] {ipLow, ipHigh}); 
     } catch (UnknownHostException e) { 
      throw new HibernateException("Failed to get InetAddress: ip = " + ipHigh + " + " + ipLow, e); 
     } 
    } 
    else 
     return null; 
} 

@Override 
public Object deepCopy(Object value) throws HibernateException { 
    if(value != null) 
     try { 
      return InetAddress.getByAddress(((InetAddress)value).getAddress()); 
     } catch (UnknownHostException e) { 
      throw new RuntimeException("Impossible Exception: " + e.getMessage(), e); 
     } 
    else 
     return null; 
} 

@Override 
public boolean isMutable() { 
    return false; 
} 
    ... 
} 

ध्यान दें कि आईपीएलओ और आईपीएचई के मूल्यों के आधार पर मैं लचीला रूप से Inet4Address और Inet6Address उदाहरणों के बीच स्विच करता हूं। समग्र को अपरिवर्तनीय के रूप में चिह्नित किया जाता है और आपको हाइबरनेट स्रोत कोड (समग्र उपयोगकर्ता प्रकारों में निर्मित) में प्रलेखन और उदाहरणों की जांच करने की आवश्यकता होती है।

इसी तरह आप अपनी सार्थक बिट गुणों को मानचित्र बना सकते हैं। आप अपने EnumType को एक एकल Restriction.eq refering का उपयोग करके उन बिट्स से पूछ सकते हैं। आप गुण वस्तु की जांच करने के लिए बराबर विधि का उपयोग कर सकते हैं। और यदि आपको एक विशेष मैप किए गए बिट को संदर्भित करने की आवश्यकता है तो आप ipLow प्रॉपर्टी/कॉलम को संदर्भित करने के लिए साइनअप Ip.ipLow में डॉट नोटेशन का उपयोग कर सकते हैं।

मुझे लगता है कि यह वही है जो आप खोज रहे हैं।

अद्यतन:

अंत इसे नीचे फोड़े अपने गुणों का सही क्रम को परिभाषित करने के। अपने StatusCompositeType कक्षा में

//immutable for simplicity 
class Status { 
    private final boolean editable; 
    private final boolean needsReview; 
    private final boolean active; 
    //... constructor + isEditable etc.. 
} 

: हाइबरनेट हमेशा एक संपत्ति का उपयोग करने के पूर्णांक सूचक मान का उपयोग करेगा

public String[] getPropertyNames() { 
    return new String [] {"editable", "needsReview", "active"}; 
} 

public Type[] getPropertyTypes() { 
    return new Type [] { BooleanType.INSTANCE, LongType.INSTANCE}; 
} 

public Object getPropertyValue(Object component, int property) throws HibernateException { 
if(component != null) { 
    Status status = (Status)component; 
    switch(property) { 
    case 1: return status.isEditable(); 
    case 2: return status.isReviewNeeded(); 
    case 3: return status.isActive(); 
    default: throw new IllegalArgumentException(); 
    } 
} 
else 
    return null; //all columns can be set to null if you allow a entity to have a null status. 
} 


public void nullSafeSet(PreparedStatement st, Object value, int index, 
    SessionImplementor session) throws HibernateException, SQLException { 

    if(value != null) { 
    Status status = (Status)value; 
    st.setBoolean(index, status.isEditable()); 
    st.setBoolean(index + 1, status.isReviewNeeded()); 
    st.setBoolean(index + 2, status.isActive()); 
    } 
    else { 
    st.setNull(index, BooleanType.INSTANCE.sqlType()); 
    st.setNull(index + 1, BooleanType.INSTANCE.sqlType()); 
    st.setNull(index + 2, BooleanType.INSTANCE.sqlType()); 
    } 
} 

public Object nullSafeGet(ResultSet rs, String[] names, 
    SessionImplementor session, Object owner) 
    throws HibernateException, SQLException { 
    Boolean isEditable = rs.getBoolean(names[0]); 
    if(!rs.wasNull()) { 
    Boolean isReviewNeeded = rs.getBoolean(names[1]); 
    Boolean isActive = rs.getBoolean(names[2]); 

    return new Status(isEditable, isReviewNeeded, isActive); 
    } 
    else 
    return null; 
} 

बाकी सीधे आगे है।उपयोगकर्ता प्रकार के लिए बराबर और हैशकोड को लागू करना याद रखें और अपना सत्र बनाने से पहले कॉन्फ़िगरेशन में टाइप जोड़ें। फैक्टरी।

एक बार जब आप सब कुछ जगह में आप एक मापदंड खोज बना सकते हैं और उपयोग कर सकते हैं:

//search for any elements that have a status of editable, no reviewNeeded and is not active (true false false). 
criteria.add(Restrictions.eq("status", new Status(true, false, false)); 

अब आप अपने listEntities विधि बन सकते हैं या तो: listEntities(Status status) या listEntities(boolean editable, boolean reviewNeeded, boolean isActive)

यदि आपको अतिरिक्त जानकारी की आवश्यकता है तो बस कंपोजिट टाइप और बेसिक टाइप टाइप कार्यान्वयन की जांच करें हाइबरनेट अपने स्रोत स्रोत (कंपोजिट टाइप और बेसिक टाइप के कार्यान्वयनकर्ताओं के लिए देखें) के भीतर प्रदान करता है। उनको समझना बहुत मदद करता है और हाइबरनेट के इस मध्यवर्ती स्तर के ज्ञान को सीखने में मदद करता है।

+0

दिलचस्प है, लेकिन क्या आप मेरे मामले में एक उदाहरण कोड प्रदान कर सकते हैं? अन्य कार्यवाही में 'इकाई' तालिका के संदर्भ में अन्य तालिका में संग्रहीत एनम प्रकार होना होगा। [उस तरह] (http://stackoverflow.com/questions/416208/jpa-map-collection-of-enums) मैं प्रत्येक 'इकाई' के लिए enums का संग्रह हो सकता है। –

+0

मैं आपके विशेष मामले के लिए कुछ और जानकारी रखने के लिए पोस्ट अपडेट करूंगा –

+0

आपके प्रयास के लिए धन्यवाद। आप यहां के आसपास के लोगों को शामिल करना कभी-कभी मुश्किल होता है। हाइबरनेट के 'कंपोजिट यूज़र टाइप' टूल पर अभी भी बेहतर दिखने के बाद, जैसा कि मैंने यहां देखा है, प्रत्येक 'सेट ' संभावित संयोजन के लिए एक विशिष्ट 'स्थिति' बनाने की आवश्यकता है। संक्षेप में, 'स्थिति' स्वयं उन संभावनाओं के एक संयोजन को पैक करता है, जिसे मेरे अपने समाधान के रूप में अच्छा माना जा सकता है, क्योंकि यह मानदंड कथन स्वयं ही पैक करता है, लेकिन 'स्टेटस कॉम्पोजिट टाइप' को भी लागू किया जाना चाहिए। हालांकि उन्हें 'इन' क्लॉज के साथ मिलान करने का मौका नहीं है जैसा कि मैंने अपने अपडेट में संदर्भित किया है। –

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