Varlık Çerçevesi DateTime için Linq


108

Uygulamamda Entity Framework kullanıyorum.

Benim masam

-Article
-period
-startDate

Eşleşen kayıtlara ihtiyacım var => DateTime.Now > startDate and (startDate + period) > DateTime.Now

Bu kodu denedim ama şimdi çalışıyor

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

Kodumu çalıştırdığımda aşağıdaki istisna oluşuyor

LINQ to Entities, 'System.DateTime AddDays (Double)' yöntemini tanımıyor ve bu yöntem bir mağaza ifadesine çevrilemez.


Ne tür period? AddDaysbir ise yanlış işlevdir double.
Craig Stuntz

Yanıtlar:


201

LINQ to Entity Framework kullanırken, Where cümlesindeki tahminleriniz SQL'e çevrilir. Bu hatayı alıyorsunuz çünkü DateTime.Add()mantıklı olan SQL'e çeviri yok .

Hızlı bir çözüm, ilk Where ifadesinin sonuçlarını belleğe okumak ve ardından filtrelemeyi bitirmek için LINQ to Objects'i kullanmak olacaktır:

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

.NET 4.0 kullanıyorsanız EntityFunctions.AddDays yöntemini de deneyebilirsiniz :

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

Not: EF 6Şimdi içinde System.Data.Entity.DbFunctions.AddDays.


42
Bu tehlikeli bir çözümdür, ToList () büyük miktarda veri döndürürse ne olur?
Stefan P.

7
EntityFunctions.AddDays ipucu için teşekkürler EF .net 4.0 kullanıyorum ama EntityFunctions'ı bilmiyordum, araştıracağım.
Stefan P.

2
@SaeedAlg - İlk örnekte öğeleri belleğe okumak gerekir. İkinci örnekte, orijinal formatla eşleşecek iki Where cümlesini tuttum. İkisini tek bir Where cümlesine sıkıştırsanız bile, Entity Framework kimlik SQL'i oluşturur, bu nedenle bu gerçekten bir okunabilirlik meselesidir.
Justin Niessner

2
@Justin Niessner çok teşekkürler, bunu dört saattir yapmaya çalışıyorum, saniyeler içinde hayatımı kurtarıyorsun tekrar teşekkürler
Yücel

2
EF ile "hızlı" çözüm sunarken, hepimiz ToList ve ToArray yöntemlerinin kullanımından kaçınmalıyız. Daha önce tarihi hesaplamak ve bu değerle karşılaştırmak kadar hızlıdır ve bu, sonuçlarını bellekte başlatmadan bir EF sorgusunda çalışır.
Isaac Llopis

92

Sanırım bu son cevabın önermek istediği şey buydu, ama p.startdat'a günler eklemeye çalışmak yerine (sql ifadesine dönüştürülemeyen bir şey) neden sql ile eşitlenebilecek bir şey yapmayalım:

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

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

2
@Adrian Carr - Bu kullanım durumu için daha iyi olabilir, ancak EntityFunctionsçözüm kadar değil. Burada, ikinci işlenen sorgudaki başka bir varlıktan alınmaz ve sorgulamadan önce hesaplanabilir. Her iki işlenen db'de bulunsaydı, EntityFunctionsçözüm yine de uygun olurken, bu yanıtın çözümü artık işe yaramazdı.
Frédéric

Bu, yanıt olarak işaretlenen çözümden daha iyi bir çözümdür. Justin / işaretli cevaptan gelen cevap, veri tabanından gereksiz sonuçlar verecektir. Bu çözüm aslında tarihi filtrelemek için SQL'de gönderir ve verileri filtrelemek için çok daha performanslı olan SQL'i kullanır.
Paul

3

DateTime'dan 2 günü çıkarmaya ne dersiniz? Şimdi:

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

Dürüst olmak gerekirse, neyi başarmaya çalıştığından emin değilim, ama bu işe yarayabilir


Makaleler Başlangıç ​​Tarihinde gösterilmeye başlayacak ve x (dönem) gün sonra sona erecektir. Yapmaya çalıştığım şey bu. Justin Niessner'ın ikinci çözümü görmek istediğim şey için çok işe yaradı
Yücel

3

İfadenizin SQL'e çevrilmesine ihtiyacınız varsa kullanmayı deneyebilirsiniz.

System.Data.Entity.Core.Objects.AddDays yöntemi.

Aslında eski olarak işaretlendi ama işe yarıyor. System.Data.Entity.DbFunctions.AddDays ile değiştirilmeli ama bulamıyorum ...


Bu, 4 yıl öncesinden kabul edilen cevaptan başka bir şey eklemiyor!
Andrew Harris

@AndrewHarris de cevabım 4 yıl önceki cevap. Cevabın ilk versiyonunda, Nereden önce bir ToList (=> veri materyalizasyonu) vardı (cevabın ilk yorumuna bakın).
bubi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.