Les arguments DbArithmeticExpression doivent avoir un type commun numérique

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(); 

Cette expression Linq lève cette exception:

DbArithmeticExpression arguments must have a numeric common type.

Veuillez aider!

Nawaz Dhandala
la source
Quels sont les résultats de clientDateTime - o.ClientDateTimeStamp?
shahkalpesh
noramlly qui devrait être un objet de TimeSpan, dans l'exception EF est levée.
Nawaz Dhandala

Réponses:

247

L'arithmétique avec DateTimen'est pas prise en charge dans Entity Framework 6 et versions antérieures. Vous devez utiliser DbFunctions *. Donc, pour la première partie de votre déclaration, quelque chose comme:

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

Notez que la DiffHoursméthode accepte Nullable<DateTime>.

Entity Framwork core (lorsqu'il est utilisé avec Sql Server, peut-être d'autres fournisseurs de base de données) prend en charge les AddXxxfonctions DateTime (comme AddHours). Ils sont traduits en DATEADDSQL.

* EntityFunctionsavant Entity Framework version 6.

Gert Arnold
la source
2

Je sais que c'est une vieille question, mais dans votre cas spécifique, au lieu d'utiliser DBFunctionscomme suggéré par @GertArnold, ne pourriez-vous pas simplement inverser l'opération pour sortir l'arithmétique en question du Lambda?

Après tout, clientDateTimeet time24sont des valeurs fixes, leur différence n'a donc pas besoin d'être recalculée à chaque itération.

Comme:

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();

Ce refactor est généralement possible si vous essayez de comparer le datetime stocké décalé par un horodatage fixe avec un autre datetime.

Bientôt Mort
la source
J'avais cette situation exacte, et cela m'a aidé. Cependant, la portée de cette solution est très limitée à un type spécifique de problème.
Zimano
@Zimano Il résout le problème des OP sans qu'il soit obligé de changer de technologie ou de recourir à des hacks. Si elle peut être refactorisée comme ceci, faites-le, sinon faites-le comme dans la réponse acceptée.
SoonDead
1

Dans l'autre sens, si la performance n'est pas le véritable objectif, vous pouvez essayer d'utiliser AsEnumerable(). Donc, ce serait comme

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

L'ajout de AsEnumerable () convertira la requête SQL en entité et permet d'exécuter des fonctions .Net dessus. Pour plus d'informations, cliquez ici sur AsEnumerable

foiré
la source