2017-11-06 17 views
9

oracle 및 Sql과 함께 엔티티 프레임 워크 6을 사용하고 있습니다. Timespan 데이터 유형이 oracle과 작동하지 않습니다. 그래서 datetime을 datetime으로 변경했습니다. 이제 Linq 쿼리와 datetime에서 시간 만 비교하고 싶습니다. 전의.엔티티 프레임 워크 6에서 odp.net으로 datetime 시간 만 비교하십시오. Oracle 12c

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

위의 예에서 e.ExecutionTime은 datetime이고 viewmodel.ExecutionTime은 timespan입니다. 쿼리를 실행하지 못했습니다 위에 내가 시간 범위

로 변환하는 기능을 timeofday 사용하고 그래서 내가 timespan.still 내가 오류 아래 얻고 전 exetime 위 DbFunctions.CreateTime() 함수

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

이다 사용

{"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())); 
} 

당신은 날짜 시간 구문 분석 - 속성을 추가 할 수 있습니다

가장 아름다운 버전은 아니지만 작동합니다.

이것은 DbFunctions의 Oracle 기반 문제입니다. sql-log를 활성화하면 알 수없는 "CREATETIME()"함수가 사용됩니다.

sql-log 활성화 : ctx.Database.Log = Console.WriteLine;

로그는 다음과 같이 표시됩니다

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

문자열에서 oracle timespan과 SQL datatime을 모두 변환 한 다음 비교할 수 있습니까? 마찬가지로 :

때문에 오라클과 날짜 - 시간이 문제의
var db0010016 = _idb0010016Rep.GetAll().Where(e => e.ExecutionTime.TimeOfDay.ToString() == viewmodel.ExecutionTime.ToString()).FirstOrDefault() 
+0

당신은 같음을 사용하여 문자열을 비교할 수 있습니다 – ceferrari

+0

날짜에 대한 문자열 비교를 사용하면 효과가 없습니다 ... –

1

을 당신이 DbFunctions (here 참조)에서 지원되는 EDM 정식 기능을 사용할 수 있습니다 만 시간을 비교하려는 경우. 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(); 
     } 

당신이 EDM 기능 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을 지원하지 않으며, 오라클 제공자는/상수를 DbFunctions.CreateTimeTimeSpan 매개 변수를 지원하지 않습니다.

다른 답변으로 제안 된대로 스토리지를 DateTime에서 string으로 전환하기 전에 몇 가지 옵션이 있습니다.

첫째, 당신은 (쿼리 매개 변수) 별도의 변수로 추출 중 한 가지 방법으로 시간 구성 요소를 비교할 수있는 평등 수표 :

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; 
    } 
} 

그것은 당신의 viewModel.ExecutionTime 유사한 DateTime.TimeOfDay 재산과 TimeSpan 클래스 속성을 변환하는 두 개의 작은 사용자 정의 ExpressionVisitor 클래스를 사용 : 내가 제공 할 수있는 것은 작은 유틸리티 클래스를 제공하는 사용자 정의 확장 방법이야.

지금이 같이 원래 쿼리를 사용해야합니다 :

대신 초 (밀리 초)을 사용하려는 경우
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;