2012-05-15 20 views
5

जहां एक तरह से कुछ इस तरह लिखने के लिए है:NHibernate LINQ प्रदाता DateDiff

public class Item 
{ 
    public DateTime Start { get; set; } 
    public DateTime Finish{ get; set; } 
} 

Sessin.Query<Item>.Where(x => x.Start.AddHours(3) > x.Finish); 

अब मैं एक अपवाद मिल

[NotSupportedException: System.DateTime AddHours (डबल)]

+0

आप NH3.3 का उपयोग कर रहे हैं? और कोड द्वारा मैपिंग? – Rippo

+0

हां, मैं –

उत्तर

7

अपने LINQ बनाने के लिए कोई आसान तरीका नहीं है प्रश्न काम आपके परिदृश्य में समस्या यह है कि एनएचबीर्नेट को पता नहीं है कि DateTime.AddHours(double hours) विधि का अनुवाद कैसे करें। लेकिन क्या आप एक समान प्रश्न लिखने के लिए एचक्यूएल का उपयोग कर सकते हैं? जाहिरा तौर पर नहीं। कोई मानक एचक्यूएल AddHours समारोह नहीं है। इसलिए आपको यह नया फ़ंक्शन पंजीकृत करना होगा। NHibernate hql और विक्रेता-विशिष्ट SQL वाक्यविन्यास के बीच अनुवाद करने के लिए बोलीभाषा का उपयोग करता है। ऐसा करने के लिए आपको एक नई बोलीभाषा वर्ग को एक exising से प्राप्त करना होगा और RegisterFunctions विधि को ओवरराइड करना होगा। लेकिन यह समस्या का केवल पहला आधा हल करता है। इसके बाद आपको LINQ में इस फ़ंक्शन का उपयोग करने के लिए NHibernate को दिखाना होगा। आपको DateTime.AddHours(double hours) विधि और प्रीवियोसी पंजीकृत कस्टम एचक्यूएल फ़ंक्शन के बीच "मानचित्र" करना होगा। NHibernate इस उद्देश्य के लिए एक रजिस्ट्री का उपयोग करता है। आपको डिफ़ॉल्ट linq-to-hql रजिस्ट्री का विस्तार करना होगा।

मैं एक उदाहरण है कि NHibernate के साथ काम किया है दिखाएगा 3.3

एक नई बोली कक्षा बनाएं (मेरे उदाहरण पूर्वनिर्धारित MsSql2008Dialect का उपयोग करता है)

 
    public class EnhancedMsSql2008Dialect : MsSql2008Dialect 
    { 
     protected override void RegisterFunctions() { 
      base.RegisterFunctions(); 
      RegisterFunction("add_hours", new SQLFunctionTemplate(NHibernateUtil.DateTime, "dateadd(hour, ?1, ?2)")); 
     } 
    } 

एक नया LINQ करने वाली HQL जनरेटर वर्ग जानता बनाएं AddHours विधि

 
    using NHibernate.Linq.Functions; 
    using NHibernate.Linq; 
    using NHibernate.Hql.Ast; 

    public class DateTimeMethodsHqlGenerator : BaseHqlGeneratorForMethod 
    { 
     public DateTimeMethodsHqlGenerator() { 
      SupportedMethods = new[] { 
       ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1)) 
      }; 
     } 

     public override HqlTreeNode BuildHql(System.Reflection.MethodInfo method, System.Linq.Expressions.Expression targetObject, System.Collections.ObjectModel.ReadOnlyCollection arguments, HqlTreeBuilder treeBuilder, NHibernate.Linq.Visitors.IHqlExpressionVisitor visitor) { 
      return treeBuilder.MethodCall("add_hours", visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(targetObject).AsExpression()); 
     } 
    } 

अनुवाद करने के लिए कैसे डिफ़ॉल्ट बढ़ाएँ LINQ करने वाली HQL रजिस्ट्री वर्ग

 
    public class EnhancedLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry 
    { 
     public EnhancedLinqToHqlGeneratorsRegistry() : base() { 
      // 
      RegisterGenerator(ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1)), new DateTimeMethodsHqlGenerator()); 
     } 
    } 

कॉन्फ़िगर

 
    cfg.DataBaseIntegration(c => { 
     c.Dialect<EnhancedMsSql2008Dialect>(); 
    }); 
    cfg.LinqToHqlGeneratorsRegistry<EnhancedLinqToHqlGeneratorsRegistry>(); 
+0

का उपयोग करें मेरे जैसा बहुत ही जवाब और बाद में पांच मिनट का उत्तर दिया :) – Rippo

+0

संपादित करते समय "नया उत्तर दिखाएं" दबाया नहीं था, क्योंकि मेरा समाधान छोड़ दिया गया था, – Vasea

+0

संपादित करने से पहले कस्टम बोलीभाषा है उत्तर और स्थिति के अच्छे विवरण के लिए धन्यवाद। डिफ़ॉल्ट LinqToHqlGenerators रजिस्ट्री में मर्ज विधि का उपयोग कर बीटीडब्ल्यू थोड़ा सुंदर दिखता है :) –

5

आप राष्ट्रीय राजमार्ग 3.3 और बातूनी विन्यास का उपयोग कर रहे हैं तो आप कुछ इस तरह कर सकते हैं ..

विन्यास को LinqToHqlGeneratorsRegistry जोड़ें: -

 var configure = new Configuration() 
      .DataBaseIntegration(x => { 
       x.Dialect<CustomDialect>(); 
       x.ConnectionStringName = "db"; 
      }) 
      .LinqToHqlGeneratorsRegistry<MyLinqtoHqlGeneratorsRegistry() 
      .CurrentSessionContext<WebSessionContext>(); 

और निम्नलिखित तीन वर्गों को जोड़ने: -

public class MyLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry 
{ 
    public MyLinqtoHqlGeneratorsRegistry() 
    { 
     this.Merge(new AddHoursGenerator()); 
    } 
} 

public class AddHoursGenerator : BaseHqlGeneratorForMethod 
{ 
    public AddHoursGenerator() 
    { 
     SupportedMethods = new[] { 
     ReflectionHelper.GetMethodDefinition<DateTime?>(d =>  
       d.Value.AddHours((double)0)) 
      }; 
    } 

    public override HqlTreeNode BuildHql(MethodInfo method, 
     System.Linq.Expressions.Expression targetObject, 
     ReadOnlyCollection<System.Linq.Expressions.Expression> arguments, 
     HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor) 
    { 
     return treeBuilder.MethodCall("AddHours", 
       visitor.Visit(targetObject).AsExpression(), 
       visitor.Visit(arguments[0]).AsExpression() 
      ); 
    } 
} 

public class CustomDialect : MsSql2008Dialect 
{ 
    public CustomDialect() 
    { 
     RegisterFunction(
      "AddHours", 
      new SQLFunctionTemplate(
        NHibernateUtil.DateTime, 
        "dateadd(hh,?2,?1)" 
       ) 
      ); 
    } 
} 

मैं इस blog post फैबियो द्वारा पर इस आधार पर किया है।

अब आप अपने कोड के रूप में उपयोग कर सकते हैं: -

Session.Query<Item>.Where(x => x.Start.AddHours(3) > x.Finish); 

यह भी 3.2 में संभव है लेकिन public override HqlTreeNode BuildHql(..) मापदंडों थोड़े अलग हैं ...

+0

दोनों का उपयोग समाधान के लिए धन्यवाद! मुझे खेद है कि मैंने एक और जवाब स्वीकार कर लिया क्योंकि इसमें क्या हो रहा है और क्यों अच्छा गुस्सा है। –

+0

चिंता न करें मुझे बहुत परेशान नहीं है हालांकि मुझे कुछ हद तक लगता है कि दूसरा जवाब हटा दिया जाना चाहिए, आप कुछ जीतते हैं जो आप कुछ खो देते हैं। – Rippo

+0

क्या डेटटाइम के साथ काम करने के लिए यह संभव है। सॉर्ट्रैक्ट? – nfplee

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