2011-01-29 19 views
12

मैं एक साथ एक जटिल क्वेरी हाइबरनेट का उपयोग कर डाल करने के लिए कोशिश कर रहा हूँ। मैं मानदंड की ओर झुका रहा हूं, लेकिन मुझे संदेह है कि यह संभव नहीं है, और इसलिए कोई सुझाव उपयोगी होगा।हाइबरनेट मापदंड को महत्व देता

मैं की तरह एक इकाई संरचना है निम्नलिखित:

public class Attribute { 
    private Integer id; 
    private String name; 
    private Set<Value> values; 
} 

public class Instance { 
    private Integer id; 
    private int instanceRef; 
    private Set<Value> values; 
} 

public class Value { 
    private Integer id; 
    private Attribute attribute; 
    private String localAttributeName; 
    private Instance instance; 
    private String value; 
} 

इन संस्थाओं से संबंधित हैं के रूप में आप उम्मीद थी:

value.attribute_id --> attribute.id 
value.instance_id --> instance.id 

अब, मैं का एक सेट लेने में सक्षम होना चाहते हैं विशेषता/मूल्य जोड़े (स्ट्रिंग्स) और उन सभी उदाहरणों को ढूंढें जिनमें सभी शामिल हैं। मान में, केवल एक विशेषता और localAttributeName गैर-शून्य हैं, इसलिए विशेषता का नाम स्थानीयAttributeName या attribute.name से मेल खा सकता है। वह है, एक उदाहरण के भीतर, किसी भी गुण हो सकता है एक से अधिक मान - और बातें एक आखिरी बार जटिल, पर मूल्य अद्वितीय सूचकांक (उदाहरण के लिए, विशेषता, मूल्य) या (उदाहरण के लिए, localAttributeName, मूल्य) पर है।

public List<Instance> getMatchingInstances(Map<String, String> attrValues) { 
    Criteria crit = session.createCriteria(Instance.class, "i"); 
    for(Map.Entry<String, String> entry : attrValues) { 
     DetachedCriteria valueCrit = DetachedCriteria.forClass(Value.class, "v"); 

     // Do something here with valueCrit 

     crit.add(Subqueries.exists(valueCrit)); 
    } 
    return crit.list(); 
} 

अनुसंधान, मेरे द्वारा की गई है कि मैं क्या है कि कुछ करो अनुभाग के लिए कोशिश की है पर आधारित है::

// This would only check localAttributeName and not attribute.name. 
    // That's okay -- once I get the rest to work, I can figure this out. 
    valueCrit.add(Restrictions.eq("localAttributeName", entry.getKey()); 
    valueCrit.add(Restrictions.eq("value", entry.getValue()); 
    valueCrit.add(Restrictions.eqProperty("v.instance_id", "i.id")); 

लेकिन इस फेंकता

यह वही है मैं अब तक किया है नीचे दिया गया अपवाद, जो मुझे संदेह है, मुझे बता रहा है कि मैं इसे मानदंड के साथ नहीं कर सकता, लेकिन मुझे अन्यथा सीखना अच्छा लगेगा:

java.lang.NullPointerException 
    at org.hibernate.loader.criteria.CriteriaQueryTranslator.getProjectedTypes(CriteriaQueryTranslator.java:341) 

ऐसा करने के लिए जाने का सबसे अच्छा तरीका क्या होगा?

उत्तर

17

मैं इस पर पीटने के कुछ ही घंटों के बाद समाधान पता लगा। उम्मीद है कि यह दूसरों के लिए उपयोग है।

  1. एक प्रोजेक्शन जोड़े
  2. बनाएं से जुड़ने से
  3. ठीक से मुख्य मानदंड

मैं करने के लिए वापस सबक्वेरी नक्शा: वहाँ तीन मुख्य बिंदु यह है कि मैं बनाने के लिए यह संभव हल करने के लिए आवश्यक थे नीचे दिए गए कोड में इनमें से प्रत्येक को हाइलाइट किया है।

पहले, अपवाद से छुटकारा पाने के, मुझे पता चला कि सबक्वेरी एक प्रक्षेपण की जरूरत है, नीचे पर प्रकाश डाला। मैंने इंस्टेंस की "आईडी" संपत्ति पर अभी एक प्रक्षेपण किया है।

दूसरा, में शामिल होने के प्राप्त करने के लिए, मैं एक बाईं बाहरी में शामिल होने बनाने के लिए Criteria.createCriteria() तरीकों का इस्तेमाल किया। क्योंकि मेरे पास शामिल होने के विभिन्न स्तरों पर कई स्थितियां थीं, इसलिए मुझे शामिल मानदंडों को सहेजना पड़ा और उन्हें अलग से अभिव्यक्ति संलग्न करना पड़ा। यह मुझे subquery में मेरी या अभिव्यक्ति करने दें।

अंत में, मैं सबक्वेरी वापस मुख्य मानदंड को मैप करने के लिए एक eqProperty() खंड जोड़ने के लिए किया था। जैसे ही इसे परिणामी एसक्यूएल में होना जरूरी है, मैंने इसका इस्तेमाल किया: instance.id = i.id. क्योंकि मैंने पहले से ही "i" में इंस्टेंस मानदंड मैप किया था और यह मान मान मानदंड में जोड़ रहा था, यह SQL में अनुवादित है: v.instance_id = i.id.

यहाँ काम कर कोड है:

public List<Instance> getMatchingInstances(Map<String, String> attrValues) { 
    Criteria crit = session.createCriteria(Instance.class, "i"); 
    for(Map.Entry<String, String> entry : attrValues) { 
     String attrName = entry.getKey(); 
     String val = entry.getValue(); 

     // Create the subquery 
     DetachedCriteria valueCrit = DetachedCriteria.forClass(Value.class, "v"); 

     // Join the Attribute object (left outer join) 
     DetachedCriteria attrCrit = 
      valueCrit.createCriteria("attribute", CriteriaSpecification.LEFT_JOIN); 

     // Put together the OR statement on the Attribute joined criterion. 
     Criterion localAttr = Restrictions.eq("v.localAttributeName", attrName); 
     Criterion globalAttr = Restrictions.eq("name", attrName); 
     attrCrit.add(Restrictions.or(localAttr, globalAttr)); 

     // Simple column equality on the subquery criterion. 
     valueCrit.add(Restrictions.eq("value", val)); 

     // Map the subquery back to the outer query. 
     valueCrit.add(Restrictions.eqProperty("instance.id", "i.id")); 

     // Add the missing projection. 
     valueCrit.setProjection(Projections.property("id")); 

     // Add this subquery to the outer query. 
     crit.add(Subqueries.exists(valueCrit)); 
    } 
    return crit.list(); 
} 
+1

यह काम करता है !!! .. धन्यवाद। – Gaurav

+0

हे @ जोन, क्या आप इस समस्या से मेरी मदद कर सकते हैं? यहां लिंक है http://stackoverflow.com/questions/22919886/hibernate-criteria-filtering-by-attributes-of-collection! धन्यवाद! कुछ इसी तरह के बारे में है! – Victor

+0

हाइबरनेट का कौन सा संस्करण इस उत्तर के लिए अच्छा है? –

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