2011-06-07 14 views
6

मैं NHibernate 3.1.0 का उपयोग कर रहा है और मैं BaseHqlGeneratorForMethod का उपयोग करने और DefaultLinqToHqlGeneratorsRegistry रूप Fabio's post में विस्तार से बताया बढ़ा कर LINQ प्रदाता विस्तार करने के लिए कोशिश कर रहा हूँ के साथ संयोजन में।विस्तार LINQ, गतिशील LINQ समस्या

उदाहरण के लिए, ToString() का समर्थन करने के लिए मैंने नीचे ToStringGenerator बनाया है।

internal class ToStringGenerator : BaseHqlGeneratorForMethod 
{ 
    public ToStringGenerator() 
    { 
     SupportedMethods = new[] 
      { 
       ReflectionHelper.GetMethodDefinition<object>(x => x.ToString()) 
      }; 
    } 

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) 
    { 
     return treeBuilder.Cast(visitor.Visit(targetObject).AsExpression(), typeof(string)); 
    } 
} 

और मैं

internal class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry 
{ 
    public CustomLinqToHqlGeneratorsRegistry() 
    { 
     this.Merge(new ToStringGenerator()); 
    } 
} 

का उपयोग कर आदि अभी तक यह "स्थिर" प्रश्नों के लिए काम करता है, मैं इसे इस तरह उपयोग कर सकते हैं पंजीकृत किया है:

var results = mSession.Query<Project>(); 
string pId = "1"; 
results = results.Where(p => p.Id.ToString().Contains(pId)); 

यह करने के लिए सही ढंग से अनुवाद करता है इसके एसक्यूएल समकक्ष (एसक्यूएल सर्वर 2008 का उपयोग कर)

where cast(project0_.Id as NVARCHAR(255)) like (''%''[email protected]+''%'') 

समस्या पैदा होती है जब मैं इस तरह माइक्रोसॉफ्ट गतिशील LINQ पुस्तकालय (this Scott Guthrie's post में चर्चा) के साथ संयोजन में इसका इस्तेमाल करने की कोशिश:

var results = mSession.Query<Project>(); 
string pId = "1"; 
results = results.Where("Id.ToString().Contains(@0)", pId); 

यह "System.String ToString के संदेश के साथ एक NotSupportedException में जो परिणाम() "(जो ऊपर वर्णित कक्षाओं को लागू करने से पहले स्थिर प्रश्नों के साथ सटीक वही संदेश था)। इस अपवाद को "एनएचबेर्नेट" और "" पर स्टैकट्रेस के साथ एनएचबर्ननेट.लिंक.विजिटर.एचक्लजेनरेटर एक्स्पेरेशन ट्रीविज़िटर। विज़िटमैथेटर कैलएक्सप्रेस (विधिकॉलएक्सप्रेस अभिव्यक्ति) "के स्रोत के साथ फेंक दिया जा रहा है।

तो मैं यहां क्या खो रहा हूं? मैंने गलत क्या किया है, या इस परिदृश्य का समर्थन करने के लिए क्या करने की आवश्यकता है?

उत्तर

3

मुझे एक ही समस्या थी और इसे ठीक किया गया।
सबसे पहले मैं जानकारी प्रदान करने के लिए मुर्की को धन्यवाद देना चाहता हूं जो मुझे मेरे रास्ते पर पहुंचा!

उत्तर फैबियो के पोस्ट में आंशिक रूप से है। इस समस्या को हल करने के लिए आपको CustomLinqToHqlGeneratorsRegistry कन्स्ट्रक्टर में Merge विधि के बजाय RegisterGenerator का उपयोग करना होगा।

public class CustomLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry 
{ 
    public CustomLinqToHqlGeneratorsRegistry() 
     : base() 
    { 
     MethodInfo toStringMethod = ReflectionHelper.GetMethodDefinition<int>(x => x.ToString()); 
     RegisterGenerator(toStringMethod, new ToStringGenerator()); 
    } 
} 
+0

यह मर्ज कार्यान्वयन में एक बग की तरह लगता है। – murki

1

वहाँ दो, अच्छी तरह से परिभाषित, अलग यहाँ चरण हैं:

  1. एक स्थिर अभिव्यक्ति (गतिशील Linq पुस्तकालय द्वारा किया जाता)
  2. पार्स है कि एक HqlTree में में गतिशील (स्ट्रिंग) क्वेरी परिवर्तित, तो क्रियान्वित (NHibernate द्वारा किया जाता)

जब से तुम निर्धारित किया है कि एक स्थिर अभिव्यक्ति अच्छी तरह से काम करता है, समस्या 1.

में निहित है

यदि आप निम्न कार्य करते हैं तो क्या होता है?

var results = Enumerable.Empty<Project>().AsQueryable(); 
string pId = "1"; 
results = results.Where("Id.ToString().Contains(@0)", pId); 

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

सेमी-संबंधित: ToStringGenerator उपयोगी दिखता है; क्या आप NHibernate के लिए पैच सबमिट कर सकते हैं?http://jira.nhforge.org

+0

अपने जवाब के लिए धन्यवाद: CustomLinqToHqlGeneratorsRegistry वर्ग की मेरी कार्यान्वयन इस प्रकार है। मैंने जो किया है वह मैंने किया है और क्वेरी ठीक काम करती है (मेरा मतलब है कि यह कोई परिणाम नहीं देता है लेकिन क्वेरी के अंदर अभिव्यक्ति सही ढंग से जेनरेट की जाती है)। कुछ जो मैंने देखा है अब 2 प्रश्नों की तुलना करना यह है कि स्थैतिक व्यक्ति के लिए अभिव्यक्ति अभिव्यक्ति का उपयोग करती है। परिवर्तनीय (पीआईडी) मान के साथ कॉन्स्टेंट जबकि गतिशील एक सीधे स्ट्रिंग मान का उपयोग करता है। क्या आपको लगता है कि इसे समस्या से निपटना पड़ सकता है? – murki

+1

@murki: हाँ, यह संबंधित हो सकता है। उच्च प्रतिबाधा अभिव्यक्ति पेड़ छोटे बदलावों के लिए उनके समर्थन में बेहद नाजुक हैं। अब, यह दिया गया है कि आपके पास दो पथ हैं: डायनामिक लिंक को उत्सर्जित करने के लिए डायनामिक लिंक को पैच करना। अभिव्यक्ति को छोड़ना, या डायनेमिक लिंक द्वारा उत्सर्जित उपयोग का समर्थन करने के लिए एनएचबेर्नेट को पैच करना। –

0

वर्ग Project की संपत्ति Id यह एक Int32 है मान लें कि आपके ToStringGenerator वर्ग के संबंधित Int32.ToString() विधि पंजीकृत करने का प्रयास।

... 
public ToStringGenerator() 
{ 
    SupportedMethods = new[] 
     { 
      ReflectionHelper.GetMethodDefinition<object>(x => x.ToString()), 
      ReflectionHelper.GetMethodDefinition<int>(x => x.ToString()), 
     }; 
} 
... 
+0

हाँ, यह एक इंट 32 है, लेकिन मैं वास्तव में पहले कोशिश करता था -और यह शायद किसी अन्य प्रश्न के लिए विषय है, लेकिन: 1) अगर मैं केवल अपनी वस्तु में वस्तु और int कुछ भी नहीं डालता, 2) यदि मैं अधिक डेटा डालना शुरू करता हूं प्रकार (जैसे डेटटाइम), यह सत्र फ़ैक्टरी बनाने के दौरान त्रुटि के साथ एक निबर्ननेट अपवाद को फेंकता है "एक ही कुंजी वाला एक आइटम पहले ही जोड़ा जा चुका है"। – murki

+0

ठीक है धन्यवाद। कुछ जांच के बाद, एनटीबर्ननेट 3.2, अभी भी बीटा संस्करण में, लिंक में ToString समर्थन में बनाया जाएगा। –