LinqからEntityFrameworkの日時


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 to Entitiesは、メソッド 'System.DateTime AddDays(Double)'メソッドを認識しないため、このメソッドをストア式に変換できません。


タイプはperiod何ですか?AddDaysの場合、これは間違った関数ですdouble
Craig Stuntz、2010年

回答:


201

LINQ to Entity Frameworkを使用すると、Where句内の述語がSQLに変換されます。DateTime.Add()意味のあるSQLへの変換がないため、このエラーが発生しています。

簡単な回避策は、最初のWhereステートメントの結果をメモリに読み込み、次にLINQ to Objectsを使用してフィルタリングを完了することです。

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

.NET 4.0を使用している場合は、EntityFunctions.AddDaysメソッドを試すこともできます。

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()が大量のデータを返すとどうなりますか?
Stefan P.

7
EntityFunctions.AddDaysのヒントをありがとうEF .net 4.0を使用していますが、EntityFunctionsについて知りませんでした。
Stefan P.

2
@SaeedAlg-最初の例では、アイテムをメモリに読み込む必要があります。2番目の例では、元の形式と一致するように2つのWhere句を保持しています。2つを単一のWhere句に圧縮しても、Entity FrameworkはID SQLを生成するため、実際には読みやすさの問題になります。
Justin Niessner、2010年

2
@Justin Niessnerに感謝します。4時間実行しようとしています。私のおかげで数秒で私の命を救うことができます
Yucel

2
EFで「迅速な」回避策を提供する場合、ToListメソッドとToArrayメソッドの使用はすべて回避する必要があります。以前に日付を計算してその値と比較するのも同じくらい簡単で、結果をメモリにインスタンス化せずにEFクエリで機能します。
Isaac Llopis

92

私はこれがその最後の答えが提案しようとしていたものだと思いますが、p.startdat(sqlステートメントに変換できないもの)に日数を追加しようとするのではなく、sqlに等しいものを実行しないのはなぜですか。

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

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

2
@Adrian Carr-この使用例の方が良い場合がありますが、EntityFunctionsソリューションほど多くはありません。ここで、2番目のオペランドはクエリ内の別のエンティティから取得されず、クエリの前に計算できます。両方のオペランドがdbで見つかっEntityFunctionsた場合、この応答のソリューションは機能しなくなりますが、ソリューションは依然として適切です。
フレデリック

これは、回答としてマークされたソリューションよりも優れたソリューションです。Justin /マークされた回答からの応答は、データベースから不要な結果を返します。このソリューションは、実際にはSQLで日付を送信し、SQLを使用してSQLを使用してデータを除外します。これにより、パフォーマンスが大幅に向上します。
ポール

3

DateTime.Nowから2日を引くとどうでしょうか。

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

正直なところ、あなたが何を達成しようとしているのかはわかりませんが、これでうまくいくかもしれません


記事はStartDateに表示され始め、x(period)日後に終了します。これは私がやろうとしていることです。ジャスティンNiessnerの第2の解決策は、私が見たいもののために非常によく働いた
ユジェル

3

式をSQLに変換する必要がある場合は、使用してみることができます

System.Data.Entity.Core.Objects.AddDaysメソッド。

実際には時代遅れとマークされていますが、機能します。System.Data.Entity.DbFunctions.AddDaysに置き換える必要がありますが、見つかりません...


これは、4年前から受け入れられた回答にすぎません。
Andrew Harris

@AndrewHarrisまた、私の答えは4年前の答えです。回答の最初のバージョンでは、Where(回答の最初のコメントを参照)の前にToList(=>データ実体化)がありました。
bubi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.