zapytania EF6 tłumacz nie obsługuje DateTime.TimeOfDay
i dostawca Oracle nie obsługuje DbFunctions.CreateTime
i TimeSpan
parametry/stałe.
Nadal istnieje kilka opcji przed przełączeniem pamięci z DateTime
na string
zgodnie z sugestią innej odpowiedzi.
Po pierwsze, dla kontroli równości można porównać komponenty momencie przez każdą wydobywania ich w oddzielnych zmiennych (parametry zapytań):
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();
lub do fałszywej DateTime
zmiennym (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();
Po drugie, możesz pracować z czasem konwertowanym na sekundy. Pozwala to również wykonać dowolne porównanie:
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();
Ale robienie tego ręcznie jest dość denerwujące i podatne na błędy. Co mogę zaoferować jest s mały klasy narzędzie metoda dostarczaniu niestandardowych rozszerzeń:
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;
}
}
Wykorzystuje dwa małe zwyczaj ExpressionVisitor
klas do konwersji DateTime.TimeOfDay
własności i TimeSpan
klasy właściwości podobne do viewModel.ExecutionTime
.
Teraz powinieneś używać oryginalnego kwerendy tak:
var db0010016 = _idb0010016Rep.GetAll()
.Where(e => e.ExecutionTime.TimeOfDay == viewmodel.ExecutionTime)
.ConvertTimeStamps() // the magic happens here
.FirstOrDefault();
W przypadku, gdy chcesz użyć milisekund zamiast sekund, co potrzebne jest, aby zmienić pierwsze dwa oświadczenia w TimeSpanConverter
klasy następująco:
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;
Jaki błąd pojawia się po uruchomieniu pierwszego kodu? –
Wygląda na duplikat https://stackoverflow.com/questions/39822588/how-to-convert-datetime-to-timespan-in-entity-framework-query?rq=1. Sprawdź tę odpowiedź, ponieważ jest lepsza niż konwersja rzeczy na ciągi! – user2612030