Linq ke EntityFramework DateTime

108

Dalam aplikasi saya, saya menggunakan Entity Framework.

Meja Saya

-Article
-period
-startDate

Saya membutuhkan catatan yang cocok => DateTime.Now > startDate and (startDate + period) > DateTime.Now

Saya mencoba kode ini tetapi sekarang berfungsi

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

Ketika saya menjalankan kode saya, pengecualian berikut terjadi

LINQ ke Entitas tidak mengenali metode metode 'System.DateTime AddDays (Double)', dan metode ini tidak dapat diterjemahkan ke dalam ekspresi toko.

Yucel
sumber
Jenis apakah period? AddDaysadalah fungsi yang salah jika itu a double.
Craig Stuntz

Jawaban:

201

Saat menggunakan LINQ ke Entity Framework, predikat Anda di dalam klausa Where akan diterjemahkan ke SQL. Anda mendapatkan kesalahan itu karena tidak ada terjemahan ke SQL DateTime.Add()yang masuk akal.

Solusi cepatnya adalah membaca hasil dari pernyataan Where pertama ke dalam memori dan kemudian menggunakan LINQ ke Objek untuk menyelesaikan pemfilteran:

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

Anda juga dapat mencoba metode EntityFunctions.AddDays jika Anda menggunakan .NET 4.0:

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

Catatan: EF 6Sekarang System.Data.Entity.DbFunctions.AddDays.

Justin Niessner
sumber
42
Ini adalah penyelesaian yang berbahaya, apa yang terjadi jika ToList () mengembalikan sejumlah besar data?
Stefan P.
7
Terima kasih untuk EntityFunctions.AddDays tip Saya menggunakan EF .net 4.0 tetapi saya tidak tahu tentang EntityFunctions, akan memeriksanya.
Stefan P.
2
@SaeedAlg - Pada contoh pertama, Anda perlu membaca item ke dalam memori. Dalam contoh kedua saya menyimpan dua klausa Where agar sesuai dengan format aslinya. Bahkan jika Anda memampatkan keduanya menjadi satu klausa Where, Entity Framework menghasilkan identitas SQL sehingga ini benar-benar masalah keterbacaan.
Justin Niessner
2
@Justin Niessner terima kasih banyak, saya mencoba melakukan itu selama empat jam, Anda menyelamatkan hidup saya dalam hitungan detik terima kasih lagi
Yucel
2
Saat memberikan solusi "cepat" dengan EF, kita semua harus menghindari penggunaan metode ToList dan ToArray. Ini sama cepatnya dengan menghitung tanggal sebelumnya dan membandingkannya dengan nilai itu, dan itu berfungsi dalam kueri EF tanpa membuat contoh hasilnya di memori.
Isaac Llopis
92

Saya pikir inilah yang coba disarankan oleh jawaban terakhir, tetapi daripada mencoba menambahkan hari ke p.startdat (sesuatu yang tidak dapat diubah menjadi pernyataan sql) mengapa tidak melakukan sesuatu yang dapat disamakan dengan sql:

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

something.Where(p => p.startdate >= baselineDate)
Andrew
sumber
2
@Adrian Carr - Ini bisa lebih baik untuk kasus penggunaan ini tetapi tidak sebanyak EntityFunctionssolusinya. Di sini, operan kedua tidak diambil dari entitas lain dalam kueri dan dapat dihitung sebelum melakukan kueri. Jika kedua operan ditemukan dalam db, EntityFunctionssolusi akan tetap sesuai sementara solusi dari respons ini tidak berfungsi lagi.
Frédéric
Ini adalah solusi yang lebih baik daripada solusi yang ditandai sebagai jawaban. Tanggapan dari Justin / jawaban yang ditandai akan mengembalikan hasil yang tidak perlu dari database. Solusi ini sebenarnya mengirimkan tanggal di SQL di mana menyaring dan menggunakan SQL untuk menyaring data, yang jauh lebih berkinerja.
Paul
3

Bagaimana kalau mengurangi 2 hari dari DateTime.Now:

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

Sejujurnya, saya tidak yakin apa yang ingin Anda capai, tetapi ini mungkin berhasil

TimC
sumber
Artikel akan mulai ditampilkan pada StartDate dan berakhir setelah x (periode) hari. Inilah yang saya coba lakukan. Solusi kedua Justin Niessner bekerja sangat baik untuk apa yang ingin saya lihat
Yucel
3

Jika Anda membutuhkan ekspresi Anda diterjemahkan ke SQL, Anda dapat mencoba menggunakan

System.Data.Entity.Core.Objects.AddDays.

Sebenarnya ditandai usang tetapi berfungsi. Ini harus diganti dengan System.Data.Entity.DbFunctions.AddDays tetapi saya tidak dapat menemukannya ...

bubi
sumber
Ini menambahkan tidak lebih dari jawaban yang diterima dari 4 tahun sebelumnya!
Andrew Harris
@AndrewHarris juga jawaban saya adalah 4 tahun lalu jawaban. Di versi pertama jawaban ada ToList (=> materialisasi data) sebelum Di mana (lihat komentar pertama dari jawaban).
bubi