115 votes

Linq vers EntityFramework DateTime

Dans mon application, j'utilise Entity Framework.

Ma table

-Article
-period
-startDate

J'ai besoin d'enregistrements qui correspondent à => DateTime.Now > startDate and (startDate + period) > DateTime.Now

J'ai essayé ce code mais il ne fonctionne plus

Context.Article
    .Where(p => p.StartDate < DateTime.Now)
    .Where(p => p.StartDate.AddDays(p.Period) > DateTime.Now)

Lorsque j'exécute mon code, l'exception suivante se produit

LINQ to Entities ne reconnaît pas la méthode 'System.DateTime AddDays(Double)', et cette méthode ne peut pas être traduite en une expression de magasin.

0 votes

Quel type est period ? AddDays est la mauvaise fonction s'il s'agit d'un double .

212voto

Justin Niessner Points 144953

Lorsque vous utilisez LINQ to Entity Framework, vos prédicats dans la clause Where sont traduits en SQL. Vous obtenez cette erreur parce qu'il n'y a pas de traduction en SQL pour la clause DateTime.Add() ce qui est logique.

Une solution rapide serait de lire les résultats de la première instruction Where en mémoire, puis d'utiliser LINQ to Objects pour terminer le filtrage :

Context.Article.Where(p => p.StartDate < DateTime.Now)
               .ToList()
               .Where(p => p.StartDate.AddDays(p.Period) > DateTime.Now);

Vous pouvez également essayer le EntityFunctions.AddDays si vous utilisez .NET 4.0 :

Context.Article.Where(p => p.StartDate < DateTime.Now)
               .Where(p => EntityFunctions.AddDays(p.StartDate, p.Period)
                   > DateTime.Now);

Note : En EF 6 c'est maintenant System.Data.Entity.DbFunctions.AddDays .

42 votes

C'est une solution dangereuse, que se passe-t-il si ToList() renvoie une grande quantité de données ?

0 votes

@Stefan P. - Alors la première déclaration lirait une énorme quantité de données en mémoire. La deuxième méthode devrait convenir, mais elle n'est disponible qu'avec .NET 4.0.

7 votes

Merci pour l'astuce EntityFunctions.AddDays. J'utilise EF .net 4.0 mais je ne connaissais pas les EntityFunctions, je vais y réfléchir.

95voto

andrew Points 388

Je pense que c'est ce que la dernière réponse essayait de suggérer, mais plutôt que d'essayer d'ajouter des jours à p.startdat (quelque chose qui ne peut pas être converti en une instruction sql) pourquoi ne pas faire quelque chose qui peut être assimilé à sql :

var baselineDate = DateTime.Now.AddHours(-24);

something.Where(p => p.startdate >= baselineDate)

3 votes

@Adrian Carr - Il peut être meilleur pour ce cas d'utilisation, mais pas pour autant que la EntityFunctions solution. Ici, le second opérande n'est pas récupéré d'une autre entité dans la requête et peut être calculé avant la requête. Si les deux opérandes devaient être trouvés dans la base de données, l'option EntityFunctions serait toujours adaptée, alors que la solution de cette réponse ne fonctionnerait plus.

0 votes

Cette solution est meilleure que la solution indiquée comme réponse. La réponse de Justin / marquée réponse renverra des résultats inutiles de la base de données. Cette solution envoie en fait la date dans le filtre SQL where et utilise SQL pour filtrer les données, ce qui est beaucoup plus performant.

3voto

bubi Points 29

Si vous avez besoin que votre expression soit traduite en SQL, vous pouvez essayer d'utiliser

System.Data.Entity.Core.Objects.AddDays méthode.

Il est actuellement marqué comme obsolète mais il fonctionne. Il devrait être remplacé par System.Data.Entity.DbFunctions.AddDays mais je ne le trouve pas...

3voto

TimC Points 786

Que diriez-vous de soustraire 2 jours de DateTime.Now :

Context.Article
.Where(p => p.StartDate < DateTime.Now)
.Where(p => p.StartDate > DateTime.Now.Subtract(new TimeSpan(2, 0, 0, 0)))

Pour être honnête, je ne suis pas sûr de ce que vous essayez d'obtenir, mais ceci peut fonctionner.

0 votes

Les articles commenceront à être affichés à StartDate et se termineront après x(période) jours. C'est ce que j'essaie de faire. La deuxième solution de Justin Niessner a très bien fonctionné pour ce que je veux voir.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X