2009-03-23 17 views
15

इस प्रश्न के लिए, हम एक विशेष क्वेरी लिखने से बचना चाहते हैं क्योंकि क्वेरी को कई डेटाबेस में अलग होना होगा। केवल हाइबरनेट मानदंडों का उपयोग करके, हम विशेष पात्रों से बचने में सक्षम होना चाहते हैं।हाइबरनेट मानदंडों का उपयोग करना, क्या विशेष पात्रों से बचने का कोई तरीका है?

मान लें कि हम डेटाबेस में तालिका 'foo' है:

यह स्थिति विशेष वर्ण से बचें करने की क्षमता की आवश्यकता होगी, के लिए कारण है। तालिका 'foo' में केवल 1 फ़ील्ड है, जिसे 'नाम' कहा जाता है। 'नाम' फ़ील्ड में वे वर्ण हो सकते हैं जिन्हें डेटाबेस में विशेष माना जा सकता है। ऐसे नाम के दो उदाहरण 'name_1' और 'name% 1' हैं। '_' और '%' दोनों कम से कम ओरेकल में विशेष वर्ण हैं। यदि कोई उपयोगकर्ता डेटाबेस में दर्ज किए जाने के बाद इन उदाहरणों में से किसी एक को खोजना चाहता है, तो समस्याएं हो सकती हैं।

criterion = Restrictions.ilike("name", searchValue, MatchMode.ANYWHERE); 
return findByCriteria(null, criterion); 

इस कोड में, 'searchValue' वह मान है जिसे उपयोगकर्ता ने अपनी खोज के लिए उपयोग करने के लिए आवेदन दिया है। यदि उपयोगकर्ता '%' खोजना चाहता है, तो उपयोगकर्ता डेटाबेस में प्रत्येक 'foo' प्रविष्टि के साथ वापस लौटाएगा। इसका कारण यह है '%' चरित्र 'वर्णों की संख्या "का प्रतिनिधित्व करता है स्ट्रिंग मिलान और SQL कोड के लिए वाइल्डकार्ड कि हाइबरनेट का उत्पादन तरह दिखेगा:

select * from foo where name like '%' 

वहाँ एक रास्ता कुछ वर्णों से बचने के लिए हाइबरनेट बताने के लिए है, या एक वर्कअराउंड बनाने के लिए जो डेटाबेस प्रकार विशिष्ट नहीं है?

उत्तर

10

LikeExpression के रचनाकार सभी सुरक्षित हैं, इसलिए यह एक व्यवहार्य विकल्प नहीं है। इसके अलावा, इसमें problems of its own है।

एक सहयोगी और मैंने एक पैच बनाया जो बहुत अच्छी तरह से काम करता है। पैच का सारांश यह है कि LikeExpression कन्स्ट्रक्टर जो एक मैचमोड का उपभोग करता है, हम विशेष पात्रों से बचते हैं। एक चरित्र (बचने वाला चरित्र) का उपभोग करने वाले निर्माता के लिए, हम मानते हैं कि उपयोगकर्ता अपने विशेष पात्रों से बच निकलता है।

हमने यह भी सुनिश्चित करने के लिए बचने वाले वर्ण को पैरामीटर किया है कि यह SQL क्वेरी को भ्रष्ट नहीं कर सकता है अगर वे कुछ या \ quot उद्धरण चरित्र का उपयोग करते हैं।

package org.hibernate.criterion; 

import org.hibernate.Criteria; 
import org.hibernate.HibernateException; 
import org.hibernate.dialect.Dialect; 
import org.hibernate.engine.TypedValue; 

public class LikeExpression implements Criterion { 
    private final String propertyName; 
    private final String value; 
    private final Character escapeChar; 

    protected LikeExpression(
      String propertyName, 
      Object value) { 
     this(propertyName, value.toString(), (Character) null); 
    } 

    protected LikeExpression(
      String propertyName, 
      String value, 
      MatchMode matchMode) { 
     this(propertyName, matchMode.toMatchString(value 
       .toString() 
       .replaceAll("!", "!!") 
       .replaceAll("%", "!%") 
       .replaceAll("_", "!_")), '!'); 
    } 

    protected LikeExpression(
      String propertyName, 
      String value, 
      Character escapeChar) { 
     this.propertyName = propertyName; 
     this.value = value; 
     this.escapeChar = escapeChar; 
    } 

    public String toSqlString(
      Criteria criteria, 
      CriteriaQuery criteriaQuery) throws HibernateException { 
     Dialect dialect = criteriaQuery.getFactory().getDialect(); 
     String[] columns = criteriaQuery.getColumnsUsingProjection(criteria, propertyName); 
     if (columns.length != 1) { 
      throw new HibernateException("Like may only be used with single-column properties"); 
     } 
     String lhs = lhs(dialect, columns[0]); 
     return lhs + " like ?" + (escapeChar == null ? "" : " escape ?"); 

    } 

    public TypedValue[] getTypedValues(
      Criteria criteria, 
      CriteriaQuery criteriaQuery) throws HibernateException { 
     return new TypedValue[] { 
       criteriaQuery.getTypedValue(criteria, propertyName, typedValue(value)), 
       criteriaQuery.getTypedValue(criteria, propertyName, escapeChar.toString()) 
     }; 
    } 

    protected String lhs(Dialect dialect, String column) { 
     return column; 
    } 

    protected String typedValue(String value) { 
     return value; 
    } 

} 

आप सोच रहे हैं कि क्या एलएचएस और typedValue तरीकों के लिए कर रहे हैं, नए IlikeExpression उन सवालों का जवाब देना चाहिए।

public static Criterion like(String propertyName, Object value) { 
    return new LikeExpression(propertyName, value); 
} 

public static Criterion like(String propertyName, String value, MatchMode matchMode) { 
    return new LikeExpression(propertyName, value, matchMode); 
} 

public static Criterion like(String propertyName, String value, Character escapeChar) { 
    return new LikeExpression(propertyName, value, escapeChar); 
} 

public static Criterion ilike(String propertyName, Object value) { 
    return new IlikeExpression(propertyName, value); 
} 

public static Criterion ilike(String propertyName, String value, MatchMode matchMode) { 
    return new IlikeExpression(propertyName, value, matchMode); 
} 

public static Criterion ilike(String propertyName, String value, Character escapeChar) { 
    return new IlikeExpression(propertyName, value, escapeChar); 
} 

संपादित करें:: ओह, हाँ

package org.hibernate.criterion; 

import org.hibernate.dialect.Dialect; 

public class IlikeExpression extends LikeExpression { 

    protected IlikeExpression(
      String propertyName, 
      Object value) { 
     super(propertyName, value); 
    } 

    protected IlikeExpression(
      String propertyName, 
      String value, 
      MatchMode matchMode) { 
     super(propertyName, value, matchMode); 

    } 

    protected IlikeExpression(
      String propertyName, 
      String value, 
      Character escapeChar) { 
     super(propertyName, value, escapeChar); 
    } 

    @Override 
    protected String lhs(Dialect dialect, String column) { 
     return dialect.getLowercaseFunction() + '(' + column + ')'; 
    } 

    @Override 
    protected String typedValue(String value) { 
     return super.typedValue(value).toLowerCase(); 
    } 

} 

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

1

यदि आप सीधे LikeExpression का उपयोग करते हैं, तो यह आपको बचने के चरित्र को निर्दिष्ट करने में सक्षम बनाता है। मुझे लगता है कि आपको बस इतना ही चाहिए।

+0

धन्यवाद। उम्मीद है कि मैं आज बाद में कोशिश करने का समय पा सकता हूं। मैं कोशिश करने के बाद अद्यतन करूँगा। –

+0

IlikeExpression हालांकि यह नहीं है। –

+0

सभी पसंद एक्स्प्रेशन के रचनाकार संरक्षित हैं, आपको उप-वर्ग और सार्वजनिक कन्स्ट्रक्टर बनाने की आवश्यकता होगी। – EkcenierK

3

यह एक बहुत साफ रास्ता यह करने के लिए नहीं है, लेकिन एक sqlRestrinction होना चाहिए आसान:

criterions.add(Restrictions.sqlRestriction(columnName+ " ilike '!%' escape '!'")); 

तुम भी एक ही सिद्धांत का उपयोग कर खोज के साथ एक शुरुआत कर सकते हैं:

criterions.add(Restrictions.sqlRestriction(columnName+ " ilike '!%%' escape '!'")); 
+1

मैंने इस समाधान के साथ शुरुआत की और यह मेरे लिए सरल प्रश्नों पर अच्छा काम करता था, लेकिन बाद में इसके साथ एक समस्या आई - अगर आपको 'कॉलमनाम' में '{alias}' प्लेसहोल्डर का उपयोग करने की आवश्यकता है, तो यह प्लेसहोल्डर हमेशा उस तालिका को संदर्भित करता है रूट इकाई को मैप किया गया है। यदि आप अपनी क्वेरी में किसी भी जॉइन का उपयोग कर रहे हैं, तो हाइबरनेट शामिल टेबल के लिए उपनाम नहीं डाल सकता है। इस मामले में, मुझे 'LikeExpression' subclassing का सहारा लेना पड़ा। – EkcenierK

+0

इससे मदद मिलती है: मैंने मानदंडों की कोशिश की .add (Restrictions.sqlRestriction (columnName + "जैसे '!%' Escape '!')); ilike मेरे लिए काम नहीं करता है – junior

0

आप का उपयोग करते हैं हाइबरनेट 3।2 +, आप LikeExpression उपवर्ग कर सकते हैं, और उसके बाद कारखाना बनाने like/ilike तरीके:

import org.hibernate.criterion.Criterion; 
import org.hibernate.criterion.LikeExpression; 
import org.hibernate.criterion.MatchMode; 

public class EscapedLikeRestrictions { 
    private EscapedLikeRestrictions() {} 

    public static Criterion likeEscaped(String propertyName, String value, MatchMode matchMode) { 
     return likeEscaped(propertyName, value, matchMode, false); 
    } 

    public static Criterion ilikeEscaped(String propertyName, String value, MatchMode matchMode) { 
     return likeEscaped(propertyName, value, matchMode, true); 
    } 

    private static Criterion likeEscaped(String propertyName, String value, MatchMode matchMode, boolean ignoreCase) { 
     return new LikeExpression(propertyName, escape(value), matchMode, '!', ignoreCase) {/*a trick to call protected constructor*/}; 
    } 

    private static String escape(String value) { 
     return value 
       .replace("!", "!!") 
       .replace("%", "!%") 
       .replace("_", "!_"); 
    } 
} 
संबंधित मुद्दे

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