web-dev-qa-db-fra.com

Les arguments DbArithmeticExpression doivent avoir un type commun numérique

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!

112

L'arithmétique avec DateTime n'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 méthode DiffHours accepte Nullable<DateTime>.

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

* EntityFunctions avant la version 6 d'Entity Framework.

229
Gert Arnold

Je sais que c'est une vieille question mais dans votre cas spécifique au lieu d'utiliser DBFunctions comme 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 clientDateTime et time24 sont 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.

2
SoonDead

Dans l'autre sens, si les performances ne sont 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 sur ces derniers. Pour plus d'informations, vérifiez ici à propos d'AsEnumerable

1
messed-up