2012-06-16 16 views
5

जब मैं स्क्वायरल में कोई क्वेरी बनाता हूं, तो यह एक क्वेरी [टी] ऑब्जेक्ट देता है। क्वेरी अभी तक निष्पादित नहीं की गई थी और जब मैं क्वेरी ऑब्जेक्ट पर पुन: प्रयास करता हूं (क्वेरी [टी] इटेबल [टी] बढ़ाता है)।स्क्वायरल: क्वेरी को स्पष्ट रूप से

किसी प्रश्न के निष्पादन के दौरान या तो लेनदेन {} या एक ट्रांज़ेक्शन {} ब्लॉक होना चाहिए।

मैं सिर्फ चयन प्रश्नों के बारे में बात कर रहा हूं और लेनदेन आवश्यक नहीं होगा, लेकिन स्क्वायरल ढांचे को उनकी आवश्यकता है।

मैं अपने आवेदन के मॉडल में एक प्रश्न बनाना चाहता हूं और इसे सीधे उस दृश्य में भेजना चाहता हूं जहां टेम्पलेट में एक दृश्य सहायक इसे डेटा देता है और डेटा प्रस्तुत करता है। यह केवल तभी संभव है जब ट्रांज़ेक्शन को {} नियंत्रक में ब्लॉक डालें (नियंत्रक में टेम्पलेट की कॉल शामिल है, इसलिए टेम्पलेट जो पुनरावृत्ति करता है वह भी अंदर है)। मॉडल में लेनदेन {} ब्लॉक डालना संभव नहीं है, क्योंकि मॉडल वास्तव में क्वेरी निष्पादित नहीं करता है।

लेकिन मेरी समझ में लेनदेन के पास नियंत्रक के साथ कुछ लेना देना नहीं है। यह मॉडल का निर्णय है जो डेटाबेस ढांचे का उपयोग करने के लिए, इसका उपयोग कैसे करें और लेनदेन का उपयोग कहां करें। तो मैं लेनदेन {} ब्लॉक मॉडल में होना चाहता हूँ।

मुझे पता है कि मैं कर सकता हूं - क्वेरी [टी] इंस्टेंस - कॉल Iterable [T] को वापस करने के बजाय। इस क्वेरी [टी] ऑब्जेक्ट पर लिस्ट करें और फिर बनाई गई सूची को वापस करें। फिर पूरी क्वेरी मॉडल में निष्पादित की जाती है और सब कुछ ठीक है। लेकिन मुझे इस दृष्टिकोण को पसंद नहीं है, क्योंकि डेटाबेस से अनुरोध किए गए सभी डेटा को इस सूची में कैश किया जाना है। मैं एक तरीका पसंद करूंगा जहां यह डेटा सीधे देखने के लिए पारित किया गया हो। मुझे परिणाम सेट स्ट्रीमिंग की MySQL सुविधा पसंद है जब यह बड़ा हो।

क्या कोई संभावना है? हो सकता है कि फ़ंक्शन क्वेरी [टी] .executeNow() जो डेटाबेस को अनुरोध भेजता है, लेनदेन को बंद करने में सक्षम है, लेकिन फिर भी MySQL स्ट्रीमिंग सुविधा का उपयोग करता है और शेष (चयनित और इसलिए निश्चित) परिणाम सेट प्राप्त करता है यह पहुंचा है? चूंकि परिणाम सेट क्वेरी के पल में तय किया गया है, लेनदेन को बंद करना कोई समस्या नहीं होनी चाहिए।

+0

यदि आप अपना समाधान पोस्ट करेंगे तो यह अच्छा होगा, आपको एक दिलचस्प/आश्चर्यजनक खोजना चाहिए। –

उत्तर

5

सामान्य समस्या यह है कि मैं यहाँ देखते हैं कि आप निम्न दो विचारों गठबंधन करने की कोशिश है:

  • डेटा के आलसी गणना; यहां: डेटाबेस परिणाम

  • एक पोस्ट-प्रोसेसिंग कार्रवाई की आवश्यकता को छिपाने की आवश्यकता है जिसे गणना पूर्ण होने पर ट्रिगर किया जाना चाहिए; यहाँ: अपने नियंत्रक से छुपा या देखने कि डेटाबेस सत्र

बंद होना चाहिए के बाद से अपने गणना आलसी है और जब से तुम बहुत अंत (यहाँ के लिए यह प्रदर्शन करने के लिए बाध्य नहीं हैं: पूरे परिणाम सेट से अधिक पुनरावृति करने के लिए), कोई स्पष्ट हुक नहीं है जो पोस्ट-प्रोसेसिंग चरण को ट्रिगर कर सकता है।

Query[T].toList का आह्वान करने का आपका सुझाव इस समस्या को प्रदर्शित नहीं करता है, क्योंकि गणना बहुत अंत तक की जाती है, और परिणाम सेट के अंतिम तत्व का अनुरोध सत्र को बंद करने के लिए ट्रिगर के रूप में उपयोग किया जा सकता है।

कहा कि, सबसे अच्छा मैं के साथ आ सकता है निम्नलिखित है, जो org.squeryl.dsl.QueryDsl._using अंदर कोड का रूपांतरण है है:

class IterableQuery[T](val q: Query[T]) extends Iterable[T] { 
    private var lifeCycleState: Int = 0 
    private var session: Session = null 
    private var prevSession: Option[Session] = None 

    def start() { 
    assert(lifeCycleState == 0, "Queries may not be restarted.") 
    lifeCycleState = 1 

    /* Create a new session for this query. */ 
    session = SessionFactory.newSession 

    /* Store and unbind a possibly existing session. */ 
    val prevSession = Session.currentSessionOption 
    if(prevSession != None) prevSession.get.unbindFromCurrentThread 

    /* Bind newly created session. */ 
    session.bindToCurrentThread 
    } 

    def iterator = { 
    assert(lifeCycleState == 1, "Query is not active.") 
    q.toStream.iterator 
    } 

    def stop() { 
    assert(lifeCycleState == 1, "Query is not active.") 
    lifeCycleState = 2 

    /* Unbind session and close it. */ 
    session.unbindFromCurrentThread 
    session.close 

    /* Re-bind previous session, if it existed. */ 
    if(prevSession != None) prevSession.get.bindToCurrentThread 
    } 
} 

ग्राहक के रूप में इस क्वेरी आवरण का उपयोग कर सकते हैं:

var manualIt = new IterableQuery(booksQuery) 
manualIt.start() 
manualIt.foreach(println) 
manualIt.stop() 
//  manualIt.foreach(println) /* Fails, as expected */ 

manualIt = new IterableQuery(booksQuery) /* Queries can be reused */ 
manualIt.start() 
manualIt.foreach(b => println("Book: " + b)) 
manualIt.stop() 

manualIt.start() का आविष्कार पहले से ही किया जा सकता है जब ऑब्जेक्ट बनाया जाता है, यानि IterableQuery के कन्स्ट्रक्टर के अंदर या ऑब्जेक्ट को नियंत्रक को पास करने से पहले।

हालांकि, संसाधनों (फाइलों, डेटाबेस कनेक्शन इत्यादि) के साथ काम करना बहुत नाजुक है, क्योंकि अपवाद के मामले में पोस्ट-प्रोसेसिंग ट्रिगर नहीं होती है। यदि आप org.squeryl.dsl.QueryDsl._using के कार्यान्वयन को देखते हैं तो आपको से अनुपलब्ध try ... finally ब्लॉक दिखाई देंगे।