2009-10-29 15 views
8

मैं एक एनएचबीर्नेट मानदंड लिख रहा हूं जो डेटा समर्थन पेजिंग का चयन करता है। मैं उपलब्ध पंक्तियों की कुल संख्या को पकड़ने के लिए, SQL Server 2005 (+) से COUNT(*) OVER() अभिव्यक्ति का उपयोग कर रहा हूं, suggested के रूप में Ayende Rahien द्वारा। मुझे उस संख्या की गणना करने में सक्षम होने की आवश्यकता है जो कुल मिलाकर कितने पेज हैं। इस समाधान की सुंदरता यह है कि मुझे पंक्ति गणना को पकड़ने के लिए दूसरी क्वेरी निष्पादित करने की आवश्यकता नहीं है।एनएचबीर्नेट मानदंडों के लिए प्रक्षेपण जोड़ना इसे डिफ़ॉल्ट इकाई चयन करने से रोकता है

हालांकि, मैं एक कार्य मानदंड लिखने के लिए प्रबंधन नहीं कर सकता (Ayende केवल एक एचक्यूएल क्वेरी प्रदान करता है)।

यहां एक SQL क्वेरी है जो दिखाती है कि मैं क्या चाहता हूं और यह ठीक काम करता है। ध्यान दें कि मैं जानबूझकर वास्तविक पेजिंग तर्क बाहर छोड़ दिया समस्या पर ध्यान केंद्रित करने के लिए:

select 
    item, rowcount() 
from 
    Item item 

ध्यान दें कि rowcount() समारोह एक कस्टम NHibernate बोली में पंजीकृत है और COUNT(*) OVER() पर ले कर जाता है:

SELECT Items.*, COUNT(*) OVER() AS rowcount 
FROM Items 

यहाँ HQL है एसक्यूएल में

एक आवश्यकता यह है कि क्वेरी एक मानदंड का उपयोग करके व्यक्त की जाती है। दुर्भाग्य से, मैं कैसे यह सही पाने के लिए पता नहीं:

var query = Session 
    .CreateCriteria<Item>("item") 
    .SetProjection(
     Projections.SqlFunction("rowcount", NHibernateUtil.Int32)); 

जब भी मैं एक प्रक्षेपण जोड़ने के लिए, NHibernate का चयन नहीं करता item (जैसे एक प्रक्षेपण के बिना यह होगा), बस rowcount() जबकि मैं वास्तव में दोनों की जरूरत है। इसके अलावा, मैं पूरी तरह से item प्रोजेक्ट प्रतीत नहीं कर सकता, केवल यह गुण है और मैं वास्तव में उन सभी को सूचीबद्ध नहीं करना चाहता हूं।

मुझे उम्मीद है कि किसी के पास इसका समाधान होगा। फिर भी धन्यवाद।

उत्तर

5

मुझे लगता है कि मानदंड में यह संभव नहीं है, इसकी कुछ सीमाएं हैं।

आप बाद में एक प्रश्न में आईडी और लोड आइटम मिल सकता है:

var query = Session 
    .CreateCriteria<Item>("item") 
    .SetProjection(Projections.ProjectionList() 
     .Add(Projections.SqlFunction("rowcount", NHibernateUtil.Int32)) 
     .Add(Projections.Id())); 

आप इसे पसंद नहीं करते हैं, HQL का उपयोग करें, आप परिणाम की अधिकतम संख्या भी निर्धारित कर सकते हैं:

IList<Item> result = Session 
    .CreateQuery("select item, rowcount() from item where ...") 
    .SetMaxResult(100) 
    .List<Item>(); 
0

CreateMultiCriteria का उपयोग करें।

आप डीबी को केवल एक हिट के साथ 2 सरल कथन निष्पादित कर सकते हैं।

+0

का उपयोग CreateMultiCriteria दो अलग-अलग एसक्यूएल प्रश्नों में परिणाम होगा उत्पन्न किया जा करने के लिए। हालांकि उन्हें एक बैच में निष्पादित किया जाएगा, फिर भी यह केवल एक ही क्वेरी निष्पादित करने के रूप में उतना ही कुशल नहीं होगा। मैं 'चयन *, COUNT (*) ओवर() आइटम से एएस पंक्ति गणना' चाहता हूं, आइटम से नहीं चुनें; CreateMultiCriteria परिदृश्य के रूप में आइटम चुनें (*) आइटम से एएस पंक्ति गणना। –

0

मुझे आश्चर्य है कि क्यों मानदंड का उपयोग करना एक आवश्यकता है। क्या आप session.CreateSQLQuery का उपयोग नहीं कर सकते? क्या तुम सच में एक क्वेरी में यह करना चाहिए, मैं आइटम वस्तुओं और गिनती वापस खींच, की तरह का सुझाव दिया है |:

select {item.*}, count(*) over() 
from Item {item} 

... इस तरह से आप आपकी क्वेरी से आइटम वस्तुओं वापस प्राप्त कर सकते, के साथ साथ गिनती। यदि आपको हाइबरनेट के कैशिंग के साथ कोई समस्या आती है, तो आप मूल क्वेरी से जुड़े क्वेरी रिक्त स्थान (इकाई/तालिका कैश) को भी कॉन्फ़िगर कर सकते हैं ताकि स्टाइल क्वेरी कैश प्रविष्टियां स्वचालित रूप से साफ़ हो जाएंगी।

+0

आपके सुझाव के लिए धन्यवाद लेकिन मैं वास्तव में मानदंड का उपयोग करके इसे करना चाहता हूं क्योंकि इस तरह से मैं विस्तार से 'सूची (प्रारंभ, सीमा, कुल पंक्ति गणना) का उपयोग करके उन्हें विस्तारित करके अपने कई मौजूदा मानदंडों को आसानी से पेजिंग लागू कर सकता हूं। इसके अलावा, शाब्दिक एसक्यूएल (सर्वर) प्रश्नों का उपयोग करके मेरा समाधान कम प्लेटफार्म अज्ञेयवादी होगा, जबकि वर्तमान समाधान जो एक अनुकूलित बोली का उपयोग करता है, शायद एक अलग डीबीएमएस को बंदरगाह के लिए बहुत आसान होगा। –

0

यदि मैं आपके प्रश्न को सही तरीके से समझता हूं, तो मेरे पास समाधान है। मैं इस समस्या के साथ काफी परेशान था।

मुझे यह सुनिश्चित करने के लिए कि मैं एक ही पृष्ठ पर हूं, मुझे तुरंत समस्या का वर्णन करने दें। मेरी समस्या पेजिंग के लिए नीचे आ गया। मैं यूआई में 10 रिकॉर्ड प्रदर्शित करना चाहता हूं, लेकिन मैं फ़िल्टर मानदंडों से मेल खाने वाले रिकॉर्ड्स की संख्या कुल जानना चाहता हूं। मैं एनएच मानदंड एपीआई का उपयोग करके इसे पूरा करना चाहता था, लेकिन पंक्ति गणना के लिए प्रक्षेपण जोड़ते समय, मेरी क्वेरी अब काम नहीं करती है, और मुझे कोई परिणाम नहीं मिलेगा (मुझे विशिष्ट त्रुटि याद नहीं है, लेकिन ऐसा लगता है कि आप क्या करते हैं हो रही है)।

यहां मेरा समाधान है (मेरे वर्तमान उत्पादन कोड से & पेस्ट करें)। ध्यान दें कि "सत्र त्रुटि" व्यापार इकाई का नाम है जिसे मैं 3 फ़िल्टर मानदंड के अनुसार, पेजडेड डेटा पुनर्प्राप्त कर रहा हूं: IsDev, IsRead, और IsResolved।

ICriteria crit = CurrentSession.CreateCriteria(typeof (SessionError)) 
    .Add(Restrictions.Eq("WebApp", this)); 

if (isDev.HasValue) 
    crit.Add(Restrictions.Eq("IsDev", isDev.Value)); 

if (isRead.HasValue) 
    crit.Add(Restrictions.Eq("IsRead", isRead.Value)); 

if (isResolved.HasValue) 
    crit.Add(Restrictions.Eq("IsResolved", isResolved.Value)); 

// Order by most recent 
crit.AddOrder(Order.Desc("DateCreated")); 

// Copy the ICriteria query to get a row count as well 
ICriteria critCount = CriteriaTransformer.Clone(crit) 
    .SetProjection(Projections.RowCountInt64()); 
critCount.Orders.Clear(); 

// NOW add the paging vars to the original query 
crit = crit 
    .SetMaxResults(pageSize) 
    .SetFirstResult(pageNum_oneBased * pageSize); 

// Set up a multi criteria to get your data in a single trip to the database 
IMultiCriteria multCrit = CurrentSession.CreateMultiCriteria() 
    .Add(crit) 
    .Add(critCount); 

// Get the results 
IList results = multCrit.List(); 

List<SessionError> sessionErrors = new List<SessionError>(); 
foreach (SessionError sessErr in ((IList)results[0])) 
    sessionErrors.Add(sessErr); 

numResults = (long)((IList)results[1])[0]; 

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

+0

ध्यान दें कि मैं रोकाउंट प्रक्षेपण का उपयोग नहीं कर रहा हूं क्योंकि इससे केवल चयनित पंक्तियों की गणना होगी और मुझे इसमें रूचि नहीं है। COUNT (*) सभी पंक्तियों की गणना करता है, हालांकि, उसे अलग से प्राप्त करने की आवश्यकता को कम करना। फिर भी, हालांकि वे बैच किए गए हैं, आप दो प्रश्नों को निष्पादित कर रहे हैं, जो कि केवल एक को निष्पादित करने से संभावित रूप से कम कुशल है। आपका समाधान अपने आप ठीक है लेकिन यह केवल एक एकल SQL क्वेरी निष्पादित करने की मेरी आवश्यकता को पूरा नहीं करता है। ठीक है, यह एक वास्तविक आवश्यकता नहीं है लेकिन मैं अभी तक अनुकूलित करने के अवसर पर हार नहीं देना चाहता हूं। –

0

मैं आपके सत्र पर SetResultTransformer() को कॉल करके कस्टम परिणाम ट्रांसफॉर्मर की जांच करने का सुझाव दूंगा।

0

वर्ग मानचित्रण में एक सूत्र प्रॉपर्टी बनानी होगी:

<property name="TotalRecords" formula="count(*) over()" type="Int32" not-null="true"/>; 

IList<...> result = criteria.SetFirstResult(skip).SetMaxResults(take).List<...>(); 
totalRecords = (result != null && result.Count > 0) ? result[0].TotalRecords : 0; 
return result; 
+0

कुल रिकॉर्ड इकाई की संपत्ति नहीं है। इस मैपिंग को जोड़ने से परिणाम कैशिंग मुद्दों में होंगे। यह भी देखें: http://stackoverflow.com/questions/1627707 – iammichael

+0

सिर के लिए धन्यवाद! मेरे मामले में, मेरे पास क्वेरी कैश सक्षम नहीं था और यह एक स्टेटलेस वेब सेवा परत के माध्यम से प्रदान किया गया था, इसलिए सत्र कभी साझा नहीं किया गया था। –

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