Argumenty DbArithmeticExpression muszą mieć wspólny typ liczbowy

120
TimeSpan time24 = new TimeSpan(24, 0, 0);
TimeSpan time18 = new TimeSpan(18, 0, 0);    

// first get today's sleeping hours
List<Model.Sleep> sleeps = context.Sleeps.Where(
    o => (clientDateTime - o.ClientDateTimeStamp < time24) && 
          o.ClientDateTimeStamp.TimeOfDay > time18 && 
          clientDateTime.TimeOfDay < time18 && 
          o.UserID == userid).ToList(); 

To wyrażenie Linq zgłasza ten wyjątek:

DbArithmeticExpression arguments must have a numeric common type.

Proszę pomóż!

Nawaz Dhandala
źródło
Jakie są tego skutki clientDateTime - o.ClientDateTimeStamp?
shahkalpesh
noramlly, który powinien być obiektem TimeSpan, w EF jest zgłaszany wyjątek.
Nawaz Dhandala

Odpowiedzi:

247

Arytmetyka z DateTimenie jest obsługiwana w Entity Framework 6 i starszych. Musisz użyć DbFunctions *. Tak więc w pierwszej części oświadczenia coś takiego:

var sleeps = context.Sleeps(o =>
    DbFunctions.DiffHours(o.ClientDateTimeStamp, clientDateTime) < 24);

Zauważ, że DiffHoursmetoda akceptuje Nullable<DateTime>.

Entity Framwork core (gdy jest używany z serwerem Sql, może inni dostawcy bazy danych ) obsługuje AddXxxfunkcje DateTime (takie jak AddHours). Są tłumaczone na język DATEADDSQL.

* EntityFunctionsprzed Entity Framework w wersji 6.

Gert Arnold
źródło
2

Wiem, że jest to stare pytanie, ale w twoim konkretnym przypadku zamiast używać DBFunctionszgodnie z sugestią @GertArnold, czy nie mógłbyś po prostu odwrócić operacji, aby usunąć daną arytmetykę z Lambdy?

Po tym wszystkim clientDateTimei time24są wartościami fix więc ich różnica nie musi być przeliczone w każdej iteracji.

Lubić:

TimeSpan time24 = new TimeSpan(24, 0, 0);
TimeSpan time18 = new TimeSpan(18, 0, 0);    

var clientdtminus24 = clientDateTime - time24;

// first get today's sleeping hours
List<Model.Sleep> sleeps = context.Sleeps.Where(
    o => (clientdtminus24 < o.ClientDateTimeStamp) && 
          o.ClientDateTimeStamp.TimeOfDay > time18 && 
          clientDateTime.TimeOfDay < time18 && 
          o.UserID == userid).ToList();

Ta refaktoryzacja jest zwykle możliwa, jeśli próbujesz porównać przechowywaną datę i godzinę przesuniętą o znacznik czasu poprawki z inną datą i godziną.

SoonDead
źródło
Miałem dokładnie taką sytuację i to pomogło. Jednak zakres tego rozwiązania jest bardzo ograniczony do określonego rodzaju problemu.
Zimano
@Zimano Rozwiązuje problem OP bez konieczności zmiany technologii lub uciekania się do hacków. Jeśli można to refaktoryzować w ten sposób, zrób to, jeśli nie, zrób to tak, jak w zaakceptowanej odpowiedzi.
WkrótceDead
1

Z drugiej strony, jeśli wydajność nie jest prawdziwym celem, możesz spróbować użyć AsEnumerable(). A więc byłoby tak

List<Model.Sleep> sleeps = context.Sleeps.AsEnumerable().Where(....

Dodanie AsEnumerable () spowoduje konwersję zapytania SQL do encji i pozwoli na uruchamianie na nich funkcji .Net. Aby uzyskać więcej informacji, sprawdź tutaj AsEnumerable

pomieszane
źródło