2017-11-06 59 views
9

मैं ओरेकल और Sql साथ इकाई की रूपरेखा 6 उपयोग कर रहा हूँ के साथ दिनांक से केवल समय की तुलना करें enitity ढांचा 6 में। टाइम्सपैन डेटाटाइप ऑरैकल के साथ काम नहीं कर रहा है। तो मैंने डेटाटाइप को डेटाटाइम में बदल दिया। अब मैं लिंक क्वेरी के साथ डेटाटाइम में केवल समय की तुलना करना चाहता हूं। पूर्व।odp.net ओरेकल 12C

var db0010016 = _idb0010016Rep.GetAll().Where(e => e.ExecutionTime.TimeOfDay == viewmodel.ExecutionTime).FirstOrDefault(); 

उपर्युक्त उदाहरण में e.ExecutionTime डेटाटाइम और व्यूमोडेल है। निष्पादन समय समय है। मैं timeofday समारोह का उपयोग कर रहा यह समयावधि

कन्वर्ट करने के लिए ऊपर क्वेरी को निष्पादित करने में विफल रहा है तो मैं इस्तेमाल किया DbFunctions.CreateTime() फ़ंक्शन

var db0010016 = _idb0010016Rep.FindBy(e => DbFunctions.CreateTime(e.ExecutionTime.Hour, e.ExecutionTime.Minute, e.ExecutionTime.Second) == exetime).FirstOrDefault(); 

पूर्व exetime ऊपर है timespan.still मैं त्रुटि नीचे हो रही है

{"Invalid parameter binding\r\nParameter name: ParameterName"} 
+1

जब आप पहला कोड चलाते हैं तो आपको क्या त्रुटि मिलती है? –

+0

https://stackoverflow.com/questions/39822588/how-to-convert-datetime-to-timespan-in-entity-framework-query?rq=1 का डुप्लिकेट जैसा लगता है। उस उत्तर को जांचें क्योंकि यह चीजों को तारों में परिवर्तित करने से बेहतर है! – user2612030

उत्तर

1
क्योंकि ओरेकल के साथ तारीख और समय-समस्याओं की

, हम इसे केवल-स्ट्रिंग कार्य करें:

using(MyDbContext ctx = new MyDbContext()) 
{ 
    TimeSpan myTime = new TimeSpan(12, 00, 00); 
    string myTimeString = myTime.ToString("hh':'mm':'ss"); 
    List<ExecutionObjects> tmp = ctx.ExecutionObjects.Where(a => a.ExecutionTime.EndsWith(myTimeString)).ToList(); 

    // Access field in source with seperated DateTime-property. 
    tmp.ForEach(e => Console.WriteLine(e.ExecutionTimeDateTime.ToShortDateString())); 
} 

स्रोत में आप एक दिनांक समय-पार्सिंग-संपत्ति जोड़ सकते हैं:

public class ExecutionObject 
{ 
    [Column("ColExecutionTime")] 
    public string ExecutionTime { get; set; } 
    [NotMapped] 
    public DateTime ExecutionTimeDateTime { 
     get 
     { 
      return DateTime.ParseExact(this.ExecutionTime, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); 
     } 
     set 
     { 
      this.ExecutionTime = value.ToString("yyyy-MM-dd HH:mm:ss"); 
     } 
    } 
} 

नहीं सबसे सुंदर संस्करण है, लेकिन काम कर रहे।

यह DbFunctions में एक Oracle आधारित समस्या है। आप को सक्रिय करते हैं एसक्यूएल-लॉग इन करें आप देखेंगे कि एक समारोह "CREATETIME()" जो अज्ञात है प्रयोग किया जाता है,।

एसक्यूएल-लॉग सक्रिय करें: ctx.Database.Log = Console.WriteLine;

लॉग इस तरह दिखेगा:

SELECT * 
    FROM "ExecutionTimes" "Extent1" 
WHERE ((((CREATETIME (EXTRACT (HOUR FROM (CAST (
[...] 
0

आप स्ट्रिंग में दोनों ओरेकल समयावधि और SQL datatime परिवर्तित कर सकते हैं और फिर यह तुलना करें। जैसा:

var db0010016 = _idb0010016Rep.GetAll().Where(e => e.ExecutionTime.TimeOfDay.ToString() == viewmodel.ExecutionTime.ToString()).FirstOrDefault() 
+0

आप तारों की तुलना करने के लिए बराबर का उपयोग कर सकते हैं – ceferrari

+0

दिनांकों पर स्ट्रिंग तुलना का उपयोग करते हुए काम नहीं करेंगे ... –

1

अगर आप केवल समय आप DbFunctions (here देखें) से समर्थित ईडीएम विहित कार्यों का उपयोग कर सकते हैं की तुलना करना चाहते। दुर्भाग्य DbFunction.CreateTime समर्थित नहीं है।

फिर भी, अगर आप सेकंड के स्तर पर, उदाहरण के लिए एक तुलना में रुचि रखते हैं, तो आप कुछ इस तरह कर सकते हैं:

 var refTime = new DateTime(2017, 12, 13, 09, 30, 31); 
     using (this.ctx = new MyContext()) 
     { 
      var results = this.ctx.Groupings.Where(e => DbFunctions.DiffSeconds(e.EndDate, refTime) % 86400 == 0).ToList(); 
     } 

यहाँ आप ईडीएम समारोह DiffSeconds का उपयोग कर सेकंड में अंतर लेने के लिए और बनाने के एक दिन में सेकंड की संख्या के साथ मॉड्यूलस।

क्वेरी निष्पादित हो जाता है जो:

select 
    "Extent1"."GROUP_TYPE" as "GROUP_TYPE", 
    "Extent1"."GROUP_ENTITY_ID" as "GROUP_ENTITY_ID", 
    "Extent1"."ITEM_ENTITY_ID" AS "ITEM_ENTITY_ID", 
    "Extent1"."DATE_START" as "DATE_START", 
    "Extent1"."DATE_END" AS "DATE_END" 
from "MYSCHEMA"."ENTITY_GROUP_REL" "Extent1" where (0 = (mod(extract(day from (cast(:p__linq__0 as timestamp(9)) - cast("Extent1"."DATE_END" as timestamp(9))))*24*60*60 + extract(hour from(cast(:p__linq__0 as timestamp(9)) - cast("Extent1"."DATE_END" as timestamp(9))))*60*60 + extract(minute from (cast(:p__linq__0 as timestamp(9)) - cast("Extent1"."DATE_END" as timestamp(9))))*60 + extract(second from (cast(:p__linq__0 as timestamp(9)) - cast("Extent1"."DATE_END" as timestamp(9)))) ,86400))) 

आप देख सकते हैं यह ओरेकल कार्यों सर्वर साइड करने के लिए सही ढंग से अनुवाद करता है।

मुझे आशा है कि यह मदद करता है,

निकॉला

1

EF6 क्वेरी अनुवादक DateTime.TimeOfDay का समर्थन नहीं करता, और Oracle प्रदाता DbFunctions.CreateTime और TimeSpan मापदंडों स्थिरांक का समर्थन नहीं करता /।

फिर भी वहाँ के रूप में एक और उत्तर ने सुझाव दिया string करने के लिए DateTime से भंडारण स्विच करने से पहले कुछ विकल्प हैं।

सबसे पहले, आप (क्वेरी पैरामीटर) अलग-अलग वैरिएबल में उन्हें निकालने या तो द्वारा समय घटकों की तुलना कर सकते समानता जांच के लिए:

var hour = viewmodel.ExecutionTime.Hours; 
var minute = viewmodel.ExecutionTime.Minutes; 
var second = viewmodel.ExecutionTime.Seconds; 

var db0010016 = _idb0010016Rep.FindBy(e => 
    e.ExecutionTime.Hour == hour && e.ExecutionTime.Minute == minute && e.ExecutionTime.Second == second) 
    .FirstOrDefault(); 

या नकली DateTime चर (queryParameter) में:

var executionTime = DateTime.Today + viewmodel.ExecutionTime; 
var db0010016 = _idb0010016Rep.FindBy(e => 
    e.ExecutionTime.Hour == executionTime.Hour && e.ExecutionTime.Minute == executionTime.Minute && e.ExecutionTime.Second == executionTime.Second) 
    .FirstOrDefault(); 

दूसरा, आप सेकेंड में परिवर्तित समय के साथ काम कर सकते हैं।

var executionTime = (int)viewmodel.ExecutionTime.TotalSeconds; 
var db0010016 = _idb0010016Rep.FindBy(e => 
    60 * 60 * e.ExecutionTime.Hour + 60 * e.ExecutionTime.Minute + e.ExecutionTime.Second == executionTime) 
    .FirstOrDefault(); 

लेकिन सभी कि मैन्युअल काफी कष्टप्रद और त्रुटि प्रवण है कर: यह आप भी किसी भी तुलना करने देता है।

public static partial class QueryableExtensions 
{ 
    public static IQueryable<T> ConvertTimeSpans<T>(this IQueryable<T> source) 
    { 
     var expr = new TimeSpanConverter().Visit(source.Expression); 
     return source == expr ? source : source.Provider.CreateQuery<T>(expr); 
    } 

    class TimeSpanConverter : ExpressionVisitor 
    { 
     static readonly Expression<Func<DateTime, int>> ConvertTimeOfDay = dt => 
      60 * (60 * dt.Hour + dt.Minute) + dt.Second; 

     static int ConvertTimespan(TimeSpan ts) => 
      60 * (60 * ts.Hours + ts.Minutes) + ts.Seconds; 

     protected override Expression VisitMember(MemberExpression node) 
     { 
      if (node.Type == typeof(TimeSpan)) 
      { 
       if (node.Member.DeclaringType == typeof(DateTime) && node.Member.Name == nameof(DateTime.TimeOfDay)) 
        return ConvertTimeOfDay.ReplaceParameter(0, base.Visit(node.Expression)); 
       // Evaluate the TimeSpan value, convert and wrap it into closure (to keep non const semantics) 
       return ConvertTimespan(base.VisitMember(node).Evaluate<TimeSpan>()).ToClosure().Body; 
      } 
      return base.VisitMember(node); 
     } 

     protected override Expression VisitBinary(BinaryExpression node) 
     { 
      if (node.Left.Type == typeof(TimeSpan)) 
       return Expression.MakeBinary(node.NodeType, Visit(node.Left), Visit(node.Right)); 
      return base.VisitBinary(node); 
     } 
    } 

    static T Evaluate<T>(this Expression source) => Expression.Lambda<Func<T>>(source).Compile().Invoke(); 

    static Expression<Func<T>> ToClosure<T>(this T value) =>() => value; 

    static Expression ReplaceParameter(this LambdaExpression source, int index, Expression target) => 
     new ParameterReplacer { Source = source.Parameters[index], Target = target }.Visit(source.Body); 

    class ParameterReplacer : ExpressionVisitor 
    { 
     public ParameterExpression Source; 
     public Expression Target; 
     protected override Expression VisitParameter(ParameterExpression node) => node == Source ? Target : node; 
    } 
} 

यह दो छोटे कस्टम ExpressionVisitor कक्षाओं का उपयोग करता है अपने viewModel.ExecutionTime के समान DateTime.TimeOfDay संपत्ति और TimeSpan वर्ग गुण परिवर्तित करने के लिए: क्या मैं की पेशकश कर सकते है छोटे उपयोगिता वर्ग उपलब्ध कराने के कस्टम विस्तार विधि है।

अब आप इस तरह आपकी मूल क्वेरी का उपयोग किया जाना चाहिए:

var db0010016 = _idb0010016Rep.GetAll() 
    .Where(e => e.ExecutionTime.TimeOfDay == viewmodel.ExecutionTime) 
    .ConvertTimeStamps() // the magic happens here 
    .FirstOrDefault(); 

आप के बजाय सेकंड के मिलीसेकेंड का उपयोग करना चाहते मामले में, आप सभी की जरूरत के रूप में इस TimeSpanConverter कक्षा में प्रथम दो बयान बदलने के लिए है:

static readonly Expression<Func<DateTime, int>> ConvertTimeOfDay = dt => 
    1000 * (60 * (60 * dt.Hour + dt.Minute) + dt.Second) + dt.Millisecond; 

static int ConvertTimespan(TimeSpan ts) => 
    1000 * (60 * (60 * ts.Hours + ts.Minutes) + ts.Seconds) + ts.Milliseconds; 
संबंधित मुद्दे