Зв'язок з EntityFramework DateTime


108

У своїй програмі я використовую Entity Framework.

Мій стіл

-Article
-period
-startDate

Мені потрібні записи, які відповідають => DateTime.Now > startDate and (startDate + period) > DateTime.Now

Я спробував цей код, але його зараз працює

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

Коли я запускаю свій код, виникає наступне виключення

LINQ Entities не розпізнає метод 'System.DateTime AddDays (Double)', і цей метод не може бути переведений у вираз зберігання.


Якого типу period? AddDaysце неправильна функція, якщо це a double.
Craig Stuntz

Відповіді:


201

Використовуючи LINQ для Entity Framework, ваші предикати всередині пункту Where переводяться в SQL. Ви отримуєте цю помилку, оскільки немає перекладу в SQL, для DateTime.Add()чого є сенс.

Швидкою обробкою буде прочитання результатів першого оператора Where в пам'яті, а потім використання LINQ для об'єктів для завершення фільтрації:

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

Ви також можете спробувати метод EntityFunctions.AddDays, якщо ви використовуєте .NET 4.0:

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

Примітка. У EF 6ньому зараз System.Data.Entity.DbFunctions.AddDays.


42
Це небезпечна обробка, що трапиться, якщо ToList () поверне величезну кількість даних?
Стефан П.

7
Дякуємо за підказку EntityFunctions.AddDays Я використовую EF .net 4.0, але я не знав про EntityFunctions, я розгляну це.
Стефан П.

2
@SaeedAlg - У першому прикладі потрібно прочитати елементи в пам'яті. У другому прикладі я зберіг два пункти де відповідати вихідному формату. Навіть якщо ви стиснути їх у єдиний пункт «Де», Entity Framework генерує ідентифікаційний SQL, тож це справді питання читабельності.
Джастін Нісснер

2
@ Джустін Нісснер дуже дякую, я намагаюся зробити це протягом чотирьох годин, ти врятуєш мені життя за лічені секунди спасибі
Юсель

2
Надаючи "швидкі" роботи з EF, ми всі повинні уникати використання методів ToList і ToArray. Так само швидко обчислити дату раніше і порівняти з цим значенням, і це працює в EF-запиті, не інстанціюючи його результати в пам'яті.
Ісаак Льопис

92

Я думаю, що саме ця остання відповідь намагалася запропонувати, але замість того, щоб намагатися додавати дні до p.startdat (те, що неможливо перетворити на оператор sql), чому б не зробити щось, що можна прирівняти до sql:

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

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

2
@Adrian Carr - Це може бути кращим для цього випадку використання, але не для стільки, скільки EntityFunctionsрішення. Тут другий операнд не отримується з іншого об'єкта в запиті і може бути обчислений перед запитом. Якби обидва операнда були знайдені в db, EntityFunctionsрішення все-таки було б придатним, поки рішення цієї відповіді більше не працюватиме.
Фредерік

Це краще рішення, ніж рішення, позначене як відповідь. Відповідь Джастіна / помічена відповідь поверне непотрібні результати з бази даних. Це рішення фактично надсилає дату в SQL, де фільтр і використовує SQL для фільтрації даних, що набагато ефективніше.
Павло

3

Як щодо віднімання 2 днів від DateTime.Now:

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

Якщо чесно, я не впевнений, чого ви намагаєтесь досягти, але це може спрацювати


Статті почнуть відображатися в StartDate та закінчуватись через x (період) днів. Це те, що я намагаюся зробити. Друге рішення Джастіна Нісснера дуже добре подіяло на те, що я хочу бачити
Юсель

3

Якщо вам потрібно, щоб ваше вираження було переведено на SQL, ви можете спробувати використовувати

System.Data.Entity.Core.Objects.AddDays метод.

Насправді позначений застарілим, але він працює. Його слід замінити System.Data.Entity.DbFunctions.AddDays, але я не можу його знайти ...


Це не додає нічого, крім прийнятої відповіді за 4 роки до цього!
Ендрю Харріс

@AndrewHarris також моя відповідь 4 роки тому відповідь. У першій версії відповіді перед «Де» (див. Перший коментар відповіді) був ToList (=> матеріалізація даних).
bubi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.