Linq đến EntityFramework DateTime


108

Trong ứng dụng của tôi, tôi đang sử dụng Entity Framework.

Bàn của tôi

-Article
-period
-startDate

Tôi cần hồ sơ phù hợp => DateTime.Now > startDate and (startDate + period) > DateTime.Now

Tôi đã thử mã này nhưng nó hiện đang hoạt động

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

Khi tôi chạy mã của mình, ngoại lệ sau xảy ra

LINQ to Entities không nhận dạng được phương thức 'System.DateTime AddDays (Double)', và phương thức này không thể được dịch thành một biểu thức lưu trữ.


Loại là periodgì? AddDayslà chức năng sai nếu đó là một double.
Craig Stuntz

Câu trả lời:


201

Khi sử dụng LINQ cho Entity Framework, các vị từ của bạn bên trong mệnh đề Where sẽ được dịch sang SQL. Bạn đang gặp lỗi đó vì không có bản dịch sang SQL DateTime.Add()nào hợp lý.

Một công việc nhanh chóng sẽ là đọc kết quả của câu lệnh Where đầu tiên vào bộ nhớ và sau đó sử dụng LINQ to Objects để hoàn tất quá trình lọc:

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

Bạn cũng có thể thử phương thức EntityFunctions.AddDays nếu bạn đang sử dụng .NET 4.0:

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

Lưu ý: Trong EF 6đó bây giờ System.Data.Entity.DbFunctions.AddDays.


42
Đây là một công việc nguy hiểm, điều gì sẽ xảy ra nếu ToList () trả về một lượng lớn dữ liệu?
Stefan P.

7
Cảm ơn về mẹo EntityFunctions.AddDays Tôi đang sử dụng EF .net 4.0 nhưng tôi không biết về EntityFunctions, sẽ xem xét nó.
Stefan P.

2
@SaeedAlg - Trong ví dụ đầu tiên, cần phải đọc các mục vào bộ nhớ. Trong ví dụ thứ hai, tôi giữ hai mệnh đề Where để phù hợp với định dạng ban đầu. Ngay cả khi bạn nén cả hai thành một mệnh đề Where, Entity Framework tạo ra SQL nhận dạng để nó thực sự là một vấn đề dễ đọc.
Justin Niessner

2
@Justin Niessner cảm ơn rất nhiều, tôi đang cố gắng để làm điều đó cho bốn giờ, giúp bạn tiết kiệm cuộc sống của tôi trong vài giây nhờ một lần nữa
Yucel

2
Khi đưa ra các giải pháp thay thế "nhanh chóng" với EF, tất cả chúng ta nên tránh sử dụng các phương thức ToList và ToArray. Việc tính toán ngày trước đó và so sánh với giá trị đó cũng nhanh chóng như vậy và hoạt động trong truy vấn EF mà không cần khởi tạo kết quả trong bộ nhớ.
Isaac Llopis

92

Tôi nghĩ đây là điều mà câu trả lời cuối cùng đó đang cố gắng đề xuất, nhưng thay vì cố gắng thêm ngày vào p.startdat (thứ không thể chuyển đổi thành câu lệnh sql) tại sao không làm điều gì đó có thể được coi là sql:

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

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

2
@Adrian Carr - Nó có thể tốt hơn cho trường hợp sử dụng này nhưng không tốt cho nhiều EntityFunctionsgiải pháp. Ở đây, toán hạng thứ hai không được truy xuất từ ​​một thực thể khác trong truy vấn và có thể được tính toán trước khi truy vấn. Nếu cả hai toán hạng được tìm thấy trong db, EntityFunctionsgiải pháp sẽ vẫn phù hợp trong khi giải pháp của phản hồi này sẽ không hoạt động nữa.
Frédéric

Đây là một giải pháp tốt hơn so với giải pháp được đánh dấu là câu trả lời. Phản hồi từ Justin / câu trả lời được đánh dấu sẽ trả về kết quả không cần thiết từ cơ sở dữ liệu. Giải pháp này thực sự gửi ngày tháng trong SQL nơi bộ lọc và sử dụng SQL để lọc ra dữ liệu, hoạt động này hiệu quả hơn nhiều.
Paul

3

Làm thế nào về việc trừ 2 ngày khỏi DateTime. Bây giờ:

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

Thành thật mà nói, tôi không chắc bạn đang cố gắng đạt được điều gì, nhưng điều này có thể hiệu quả


Các bài báo sẽ bắt đầu được hiển thị trên StartDate và kết thúc sau x (khoảng thời gian) ngày. Đây là những gì tôi đang cố gắng làm. Giải pháp thứ hai Justin Niessner đã làm việc rất tốt cho những gì tôi muốn nhìn thấy
Yucel

3

Nếu bạn cần biểu thức của mình được dịch sang SQL, bạn có thể thử sử dụng

Phương thức System.Data.Entity.Core.Objects.AddDays.

Trên thực tế được đánh dấu là lỗi thời nhưng nó hoạt động. Nó sẽ được thay thế bằng System.Data.Entity.DbFunctions.AddDays nhưng tôi không thể tìm thấy nó ...


Điều này không thêm gì ngoài câu trả lời được chấp nhận từ 4 năm trước!
Andrew Harris

@AndrewHarris cũng là câu trả lời của tôi là câu trả lời 4 năm trước. Trong phiên bản đầu tiên của câu trả lời, có Danh sách ToL (=> dữ liệu hóa) trước Vị trí (xem chú thích đầu tiên của câu trả lời).
bubi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.